diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp index f9dd05f958a..4093470f5ab 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_plugin.cpp @@ -75,7 +75,7 @@ public: messages = m; actionSelection = new QAction(tr("Selection"), mw); connect(actionSelection, SIGNAL(triggered()), this, SLOT(selection_action())); - + last_mode = 0; dock_widget = new QDockWidget("Selection", mw); dock_widget->setVisible(false); @@ -93,13 +93,11 @@ public: this, SLOT(on_Selection_type_combo_box_changed(int))); connect(ui_widget.Insertion_radio_button, SIGNAL(toggled(bool)), this, SLOT(on_Insertion_radio_button_toggled(bool))); connect(ui_widget.Brush_size_spin_box, SIGNAL(valueChanged(int)), this, SLOT(on_Brush_size_spin_box_changed(int))); - connect(ui_widget.Create_point_set_item_button, SIGNAL(clicked()), this, SLOT(on_Create_point_set_item_button_clicked())); - connect(ui_widget.Create_polyline_item_button, SIGNAL(clicked()), this, SLOT(on_Create_polyline_item_button_clicked())); - connect(ui_widget.Erase_selected_facets_button, SIGNAL(clicked()), this, SLOT(on_Erase_selected_facets_button_clicked())); - connect(ui_widget.Keep_connected_components_button, SIGNAL(clicked()), this, SLOT(on_Keep_connected_components_button_clicked())); + connect(ui_widget.validateButton, SIGNAL(clicked()), this, SLOT(on_validateButton_clicked())); connect(ui_widget.Expand_reduce_button, SIGNAL(clicked()), this, SLOT(on_Expand_reduce_button_clicked())); - connect(ui_widget.Create_polyhedron_item_button, SIGNAL(clicked()), this, SLOT(on_Create_polyhedron_item_button_clicked())); connect(ui_widget.Select_sharp_edges_button, SIGNAL(clicked()), this, SLOT(on_Select_sharp_edges_button_clicked())); + connect(ui_widget.modeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_ModeBox_changed(int))); + connect(ui_widget.editionBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_editionBox_changed(int))); QObject* scene = dynamic_cast(scene_interface); if(scene) { @@ -111,7 +109,14 @@ public: { dock_widget->hide(); } +Q_SIGNALS: + void save_handleType(); + void set_operation_mode(int); public Q_SLOTS: + void setInstructions(QString s) + { + ui_widget.instructionsLabel->setText(s); + } void selection_action() { dock_widget->show(); dock_widget->raise(); @@ -119,12 +124,17 @@ public Q_SLOTS: Scene_polyhedron_item* poly_item = getSelectedItem(); if(!poly_item || selection_item_map.find(poly_item) != selection_item_map.end()) { return; } Scene_polyhedron_selection_item* new_item = new Scene_polyhedron_selection_item(poly_item, mw); + connect(this, SIGNAL(save_handleType()),new_item, SLOT(save_handleType())); + connect(new_item, SIGNAL(updateInstructions(QString)), this, SLOT(setInstructions(QString))); + connect(this, SIGNAL(set_operation_mode(int)),new_item, SLOT(set_operation_mode(int))); int item_id = scene->addItem(new_item); QObject* scene_ptr = dynamic_cast(scene); if (scene_ptr) connect(new_item,SIGNAL(simplicesSelected(CGAL::Three::Scene_item*)), scene_ptr, SLOT(setSelectedItem(CGAL::Three::Scene_item*))); scene->setSelectedItem(item_id); + on_ModeBox_changed(ui_widget.modeBox->currentIndex()); } + on_Selection_type_combo_box_changed(ui_widget.Selection_type_combo_box->currentIndex()); } // Select all void on_Select_all_button_clicked() { @@ -199,11 +209,19 @@ public Q_SLOTS: // all other arrangements (putting inside selection_item_map), setting names etc, // other params (e.g. k_ring) will be set inside new_item_created Scene_polyhedron_selection_item* new_item = new Scene_polyhedron_selection_item(poly_item, mw); + //To specify what action should be performed on shift+left-click + connect(this, SIGNAL(save_handleType()),new_item, SLOT(save_handleType())); + connect(new_item, SIGNAL(updateInstructions(QString)), this, SLOT(setInstructions(QString))); + connect(this, SIGNAL(set_operation_mode(int)),new_item, SLOT(set_operation_mode(int))); int item_id = scene->addItem(new_item); QObject* scene_ptr = dynamic_cast(scene); if (scene_ptr) connect(new_item,SIGNAL(simplicesSelected(CGAL::Three::Scene_item*)), scene_ptr, SLOT(setSelectedItem(CGAL::Three::Scene_item*))); scene->setSelectedItem(item_id); + ui_widget.modeBox->setCurrentIndex(last_mode); + on_ModeBox_changed(ui_widget.modeBox->currentIndex()); + on_Selection_type_combo_box_changed(ui_widget.Selection_type_combo_box->currentIndex()); + } void on_Selection_type_combo_box_changed(int index) { typedef Scene_polyhedron_selection_item::Active_handle Active_handle; @@ -222,119 +240,178 @@ public Q_SLOTS: } } - void on_Create_point_set_item_button_clicked() { - Scene_polyhedron_selection_item* selection_item = getSelectedItem(); - if(!selection_item) { - print_message("Error: there is no selected polyhedron selection item!"); - return; - } - if(selection_item->selected_vertices.empty()) { - print_message("Error: there is no selected vertex in polyhedron selection item!"); - return; - } - Scene_points_with_normal_item* point_item = new Scene_points_with_normal_item(); - point_item->setName(QString("%1-points").arg(selection_item->name())); - for(Scene_polyhedron_selection_item::Selection_set_vertex::iterator begin = selection_item->selected_vertices.begin(); - begin != selection_item->selected_vertices.end(); ++begin) { - point_item->point_set()->push_back((*begin)->point()); - } - scene->setSelectedItem( scene->addItem(point_item) ); - scene->itemChanged(point_item); - } - void on_Create_polyline_item_button_clicked(){ - Scene_polyhedron_selection_item* selection_item = getSelectedItem(); - if(!selection_item) { - print_message("Error: there is no selected polyhedron selection item!"); - return; - } - if(selection_item->selected_edges.empty()) { - print_message("Error: there is no selected edge in polyhedron selection item!"); - return; - } - Scene_polylines_item* polyline_item = new Scene_polylines_item(); - polyline_item->setName(QString("%1-edges").arg(selection_item->name())); - - typedef boost::adjacency_list < boost::listS, - boost::vecS, - boost::undirectedS, - Kernel::Point_3 > Edge_graph; - typedef Polyhedron::Vertex_handle Vertex_handle; - Edge_graph edge_graph; - std::map p2vd; - std::map::iterator it_find; - bool insert_OK; - - for(Scene_polyhedron_selection_item::Selection_set_edge::iterator begin = selection_item->selected_edges.begin(); - begin != selection_item->selected_edges.end(); ++begin) + void on_validateButton_clicked() { + switch(ui_widget.operationsBox->currentIndex()) { - Vertex_handle source = begin->halfedge()->opposite()->vertex(); - boost::tie(it_find, insert_OK) - = p2vd.insert(std::make_pair(source, Edge_graph::vertex_descriptor())); - if (insert_OK) - { - it_find->second = add_vertex(edge_graph); - edge_graph[it_find->second] = source->point(); + //Create Point Set Item from Selected Vertices + case 0: + { + Scene_polyhedron_selection_item* selection_item = getSelectedItem(); + if(!selection_item) { + print_message("Error: there is no selected polyhedron selection item!"); + return; } - Edge_graph::vertex_descriptor src=it_find->second; - - Vertex_handle target = begin->halfedge()->vertex(); - boost::tie(it_find, insert_OK) - = p2vd.insert(std::make_pair(target, Edge_graph::vertex_descriptor())); - if (insert_OK) - { - it_find->second = add_vertex(edge_graph); - edge_graph[it_find->second] = target->point(); + if(selection_item->selected_vertices.empty()) { + print_message("Error: there is no selected vertex in polyhedron selection item!"); + return; + } + Scene_points_with_normal_item* point_item = new Scene_points_with_normal_item(); + point_item->setName(QString("%1-points").arg(selection_item->name())); + for(Scene_polyhedron_selection_item::Selection_set_vertex::iterator begin = selection_item->selected_vertices.begin(); + begin != selection_item->selected_vertices.end(); ++begin) { + point_item->point_set()->push_back((*begin)->point()); + break; } - Edge_graph::vertex_descriptor tgt=it_find->second; - boost::add_edge(src, tgt, edge_graph); } + //Create Polyline Item from Selected Edges + case 1: + { + Scene_polyhedron_selection_item* selection_item = getSelectedItem(); + if(!selection_item) { + print_message("Error: there is no selected polyhedron selection item!"); + return; + } + if(selection_item->selected_edges.empty()) { + print_message("Error: there is no selected edge in polyhedron selection item!"); + return; + } + Scene_polylines_item* polyline_item = new Scene_polylines_item(); + polyline_item->setName(QString("%1-edges").arg(selection_item->name())); - Polyline_visitor polyline_visitor(polyline_item, edge_graph); - CGAL::split_graph_into_polylines( edge_graph, - polyline_visitor, - Is_terminal() ); - scene->setSelectedItem( scene->addItem(polyline_item) ); - scene->itemChanged(polyline_item); + typedef boost::adjacency_list < boost::listS, + boost::vecS, + boost::undirectedS, + Kernel::Point_3 > Edge_graph; + typedef Polyhedron::Vertex_handle Vertex_handle; + Edge_graph edge_graph; + std::map p2vd; + std::map::iterator it_find; + bool insert_OK; + + for(Scene_polyhedron_selection_item::Selection_set_edge::iterator begin = selection_item->selected_edges.begin(); + begin != selection_item->selected_edges.end(); ++begin) + { + Vertex_handle source = begin->halfedge()->opposite()->vertex(); + boost::tie(it_find, insert_OK) + = p2vd.insert(std::make_pair(source, Edge_graph::vertex_descriptor())); + if (insert_OK) + { + it_find->second = add_vertex(edge_graph); + edge_graph[it_find->second] = source->point(); + } + Edge_graph::vertex_descriptor src=it_find->second; + + Vertex_handle target = begin->halfedge()->vertex(); + boost::tie(it_find, insert_OK) + = p2vd.insert(std::make_pair(target, Edge_graph::vertex_descriptor())); + if (insert_OK) + { + it_find->second = add_vertex(edge_graph); + edge_graph[it_find->second] = target->point(); + } + Edge_graph::vertex_descriptor tgt=it_find->second; + boost::add_edge(src, tgt, edge_graph); + } + + + Polyline_visitor polyline_visitor(polyline_item, edge_graph); + CGAL::split_graph_into_polylines( edge_graph, + polyline_visitor, + Is_terminal() ); + scene->setSelectedItem( scene->addItem(polyline_item) ); + scene->itemChanged(polyline_item); + break; + } + //Create Polyhedron Item from Selected Facets + case 2: + { + Scene_polyhedron_selection_item* selection_item = getSelectedItem(); + if(!selection_item) { + print_message("Error: there is no selected polyhedron selection item!"); + return; + } + + Scene_polyhedron_item* poly_item = new Scene_polyhedron_item(); + if(selection_item->export_selected_facets_as_polyhedron(poly_item->polyhedron())) { + poly_item->setName(QString("%1-facets").arg(selection_item->name())); + poly_item->invalidateOpenGLBuffers(); // for init() + scene->setSelectedItem( scene->addItem(poly_item) ); + scene->itemChanged(poly_item); + } + else { + delete poly_item; + print_message("Error: polyhedron item is not created!"); + } + break; + } + //Erase Selected Facets from Polyhedron Item + case 3: + { + Scene_polyhedron_selection_item* selection_item = getSelectedItem(); + if(!selection_item) { + print_message("Error: there is no selected polyhedron selection item!"); + return; + } + + selection_item->erase_selected_facets(); + break; + } + //Keep connected components of Selected Facets + case 4: + { + Scene_polyhedron_selection_item* selection_item = getSelectedItem(); + if (!selection_item) { + print_message("Error: there is no selected polyhedron selection item!"); + return; + } + selection_item->keep_connected_components(); + break; + } + default : + break; + } + return; } - void on_Erase_selected_facets_button_clicked() { + void on_ModeBox_changed(int index) + { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); - if(!selection_item) { - print_message("Error: there is no selected polyhedron selection item!"); - return; + selection_item->on_Ctrlz_pressed(); + last_mode = index; + switch(index) + { + //Selection mode + case 0: + ui_widget.selection_groupBox->setVisible(true); + ui_widget.edition_groupBox->setVisible(false); + Q_EMIT set_operation_mode(-1); + on_Selection_type_combo_box_changed(ui_widget.Selection_type_combo_box->currentIndex()); + break; + //Edition mode + case 1: + ui_widget.selection_groupBox->setVisible(false); + ui_widget.edition_groupBox->setVisible(true); + Q_EMIT save_handleType(); + Q_EMIT set_operation_mode(ui_widget.editionBox->currentIndex()); + break; } - - selection_item->erase_selected_facets(); } - void on_Keep_connected_components_button_clicked() { + + void on_editionBox_changed(int mode ) + { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); - if (!selection_item) { - print_message("Error: there is no selected polyhedron selection item!"); - return; + selection_item->on_Ctrlz_pressed(); + if(ui_widget.modeBox->currentIndex() == 0) + { + Q_EMIT set_operation_mode(-1); } - selection_item->keep_connected_components(); - } - void on_Create_polyhedron_item_button_clicked() { - Scene_polyhedron_selection_item* selection_item = getSelectedItem(); - if(!selection_item) { - print_message("Error: there is no selected polyhedron selection item!"); - return; + else + { + Q_EMIT set_operation_mode(mode); } - Scene_polyhedron_item* poly_item = new Scene_polyhedron_item(); - if(selection_item->export_selected_facets_as_polyhedron(poly_item->polyhedron())) { - poly_item->setName(QString("%1-facets").arg(selection_item->name())); - poly_item->invalidateOpenGLBuffers(); // for init() - scene->setSelectedItem( scene->addItem(poly_item) ); - scene->itemChanged(poly_item); - } - else { - delete poly_item; - print_message("Error: polyhedron item is not created!"); - } } - void on_Select_sharp_edges_button_clicked() { Scene_polyhedron_selection_item* selection_item = getSelectedItem(); if (!selection_item) { @@ -431,6 +508,7 @@ private: Ui::Selection ui_widget; typedef std::multimap Selection_item_map; Selection_item_map selection_item_map; + int last_mode; }; // end Polyhedron_demo_selection_plugin //Q_EXPORT_PLUGIN2(Polyhedron_demo_selection_plugin, Polyhedron_demo_selection_plugin) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui index 59cf78f71d0..78a9977100b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Selection_widget.ui @@ -6,8 +6,8 @@ 0 0 - 455 - 528 + 479 + 606 @@ -16,136 +16,379 @@ - + + + + + + Selection Mode + + + + + Edition Mode + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + - Selection by Type + Selection Operations - + - + - - - Selection Type : + + + Selection by Type + + + + + + + Selection Type : + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Vertex + + + + + Facet + + + + + Edge + + + + + Selected components (facet) + + + + + + + + + + + + + + + + Insertion + + + true + + + + + + + Removal + + + + + + + + + + + + + Brush &size: + + + Brush_size_spin_box + + + + + + + + + + + + + + + + + + + + + Select &All + + + + + + + + + + Invert Selection + + + + + + + + + + &Clear + + + + + + + + - + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 - + - - Vertex - - - - - Facet - - - - - Edge - - - - - Selected components (facet) - - - - - - - - - - - - + - + - Insertion + Isolated &Component Size: - - true + + Threshold_size_spin_box - + + + 999999999 + + + 8 + + + + + - Removal + &Get Minimum - - - - - - - Brush &size: - - - Brush_size_spin_box - - - - - - - - - + + + Select &Isolated Components Below Threshold + + - + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + - - - - + - Select &All + Sharp edges angle: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - + + + + 0 + 0 + - - Invert Selection + + 180 + + + 60 - - - - + - &Clear + Select + + + + + + + + + + + Expand or reduce selection: + + + + + + + -50 + + + 50 + + + + + + + Apply + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Create Point Set Item from Selected Vertices + + + + + Create Polyline Item from Selected Edges + + + + + Create Polyhedron Item from Selected Facets + + + + + Erase Selected Facets from Polyhedron Item + + + + + Keep Connected Components of Selected Facets + + + + + + + + Validate @@ -156,216 +399,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - Isolated &Component Size: - - - Threshold_size_spin_box - - - - - - - 999999999 - - - 8 - - - - - - - &Get Minimum - - - - - - - - - Select &Isolated Components Below Threshold - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Sharp edges angle: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - 180 - - - 60 - - - - - - - Select - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Expand or reduce selection: - - - - - - - -50 - - - 50 - - - - - - - Apply - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Create Point Set Item from Selected Vertices - - - - - - - Create Polyline Item from Selected Edges - - - - - - - Create Polyhedron Item from Selected Facets - - - - - - - Erase Selected Facets from Polyhedron Item - - - - - - - - - - Keep connected components of Selected Facets - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -393,6 +426,94 @@ + + + + Editions Operations + + + + + + + + + Join vertex + + + + + Split vertex + + + + + Split edges + + + + + Join face + + + + + Split face + + + + + Collapse edge + + + + + Flip edge + + + + + Add center vertex + + + + + Remove center vertex + + + + + Add vertex and face to border (Advanced) + + + + + Add face to border (Advanced) + + + + + + + + Instructions + + + + + + + + + Ctrl+Z to cancel the temporary selection. + + + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.h index 50879e3877d..43bca6a90a2 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh_deformation/Scene_edit_polyhedron_item.h @@ -40,6 +40,7 @@ typedef boost::graph_traits::face_descriptor face_descriptor; typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef boost::graph_traits::edge_descriptor edge_descriptor; class Scene_spheres_item; +namespace PMP = CGAL::Polygon_mesh_processing; struct Array_based_vertex_point_map { public: diff --git a/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp index c3898da231b..6cdb7c3b043 100644 --- a/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_nef_polyhedron_item.cpp @@ -32,7 +32,7 @@ typedef CGAL::Triangulation_face_base_with_info_2 Fb1; typedef CGAL::Constrained_triangulation_face_base_2 Fb; typedef CGAL::Triangulation_data_structure_2 TDS; -typedef CGAL::No_intersection_tag Itag; +typedef CGAL::Exact_predicates_tag Itag; typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; diff --git a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp index e232c8cfb29..0819b4b65d6 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp @@ -166,7 +166,7 @@ typedef CGAL::Triangulation_face_base_with_info_2 Fb1; typedef CGAL::Constrained_triangulation_face_base_2 Fb; typedef CGAL::Triangulation_data_structure_2 TDS; -typedef CGAL::No_intersection_tag Itag; +typedef CGAL::Exact_predicates_tag Itag; typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp index 14c481bf919..8baf580b914 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp @@ -8,8 +8,6 @@ #include #include -#include - #include #include #include @@ -39,33 +37,190 @@ #include namespace PMP = CGAL::Polygon_mesh_processing; +//Used to triangulate the AABB_Tree +class Primitive +{ +public: + // types + typedef Polyhedron::Facet_iterator Id; // Id type + typedef Kernel::Point_3 Point; // point type + typedef Kernel::Triangle_3 Datum; // datum type +private: + // member data + Id m_it; // iterator + Datum m_datum; // 3D triangle + + // constructor +public: + Primitive() {} + Primitive(Datum triangle, Id it) + : m_it(it), m_datum(triangle) + { + } +public: + Id& id() { return m_it; } + const Id& id() const { return m_it; } + Datum& datum() { return m_datum; } + const Datum& datum() const { return m_datum; } + + /// Returns a point on the primitive + Point reference_point() const { return m_datum.vertex(0); } +}; -typedef CGAL::AABB_face_graph_triangle_primitive Primitive; typedef CGAL::AABB_traits AABB_traits; typedef CGAL::AABB_tree Input_facets_AABB_tree; const char* aabb_property_name = "Scene_polyhedron_item aabb tree"; -Input_facets_AABB_tree* get_aabb_tree(Scene_polyhedron_item* item) +typedef Polyhedron::Traits Traits; +typedef Polyhedron::Facet Facet; +typedef CGAL::Triangulation_2_projection_traits_3 P_traits; +typedef Polyhedron::Halfedge_handle Halfedge_handle; +struct Face_info { + Polyhedron::Halfedge_handle e[3]; + bool is_external; +}; +typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; +typedef CGAL::Triangulation_face_base_with_info_2 Fb1; +typedef CGAL::Constrained_triangulation_face_base_2 Fb; +typedef CGAL::Triangulation_data_structure_2 TDS; +typedef CGAL::Exact_predicates_tag Itag; +typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; +typedef CGAL::Constrained_triangulation_plus_2 CDT; + +//Make sure all the facets are triangles +typedef Polyhedron::Traits Kernel; +typedef Kernel::Point_3 Point; +typedef Kernel::Vector_3 Vector; +typedef Polyhedron::Halfedge_around_facet_circulator HF_circulator; +typedef boost::graph_traits::face_descriptor face_descriptor; +QList triangulate_primitive(Polyhedron::Facet_iterator fit, + Traits::Vector_3 normal) { - QVariant aabb_tree_property = item->property(aabb_property_name); - if(aabb_tree_property.isValid()) { - void* ptr = aabb_tree_property.value(); - return static_cast(ptr); + //The output list + QList res; + //check if normal contains NaN values + if (normal.x() != normal.x() || normal.y() != normal.y() || normal.z() != normal.z()) + { + qDebug()<<"Warning in triangulation of the selection item: normal contains NaN values and is not valid."; + return QList(); + } + P_traits cdt_traits(normal); + CDT cdt(cdt_traits); + + Facet::Halfedge_around_facet_circulator + he_circ = fit->facet_begin(), + he_circ_end(he_circ); + + // Iterates on the vector of facet handles + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + boost::container::flat_map v2v; + CDT::Vertex_handle previous, first; + do { + CDT::Vertex_handle vh = cdt.insert(he_circ->vertex()->point()); + v2v.insert(std::make_pair(vh, he_circ->vertex())); + if(first == 0) { + first = vh; } - else { - Polyhedron* poly = item->polyhedron(); - if(poly) { - Input_facets_AABB_tree* tree = - new Input_facets_AABB_tree(faces(*poly).first, - faces(*poly).second, - *poly); - item->setProperty(aabb_property_name, - QVariant::fromValue(tree)); - return tree; + vh->info() = he_circ; + if(previous != 0 && previous != vh) { + cdt.insert_constraint(previous, vh); + } + previous = vh; + } while( ++he_circ != he_circ_end ); + cdt.insert_constraint(previous, first); + // sets mark is_external + for(CDT::All_faces_iterator + fit2 = cdt.all_faces_begin(), + end = cdt.all_faces_end(); + fit2 != end; ++fit2) + { + fit2->info().is_external = false; + } + //check if the facet is external or internal + std::queue face_queue; + face_queue.push(cdt.infinite_vertex()->face()); + while(! face_queue.empty() ) { + CDT::Face_handle fh = face_queue.front(); + face_queue.pop(); + if(fh->info().is_external) continue; + fh->info().is_external = true; + for(int i = 0; i <3; ++i) { + if(!cdt.is_constrained(std::make_pair(fh, i))) + { + face_queue.push(fh->neighbor(i)); + } + } + } + //iterates on the internal faces to add the vertices to the positions + //and the normals to the appropriate vectors + for(CDT::Finite_faces_iterator + ffit = cdt.finite_faces_begin(), + end = cdt.finite_faces_end(); + ffit != end; ++ffit) + { + if(ffit->info().is_external) + continue; + + + res << Kernel::Triangle_3(ffit->vertex(0)->point(), + ffit->vertex(1)->point(), + ffit->vertex(2)->point()); + + } + return res; +} + + + +void* Scene_polyhedron_item::get_aabb_tree() +{ + QVariant aabb_tree_property = this->property(aabb_property_name); + if(aabb_tree_property.isValid()) { + void* ptr = aabb_tree_property.value(); + return static_cast(ptr); + } + else { + Polyhedron* poly = this->polyhedron(); + if(poly) { + + Input_facets_AABB_tree* tree = + new Input_facets_AABB_tree(); + typedef Polyhedron::Traits Kernel; + int index =0; + Q_FOREACH( Polyhedron::Facet_iterator f, faces(*poly)) + { + if(!f->is_triangle()) + { + Traits::Vector_3 normal = f->plane().orthogonal_vector(); //initialized in compute_normals_and_vertices + index +=3; + Q_FOREACH(Kernel::Triangle_3 triangle, triangulate_primitive(f,normal)) + { + Primitive primitive(triangle, f); + tree->insert(primitive); + } } - else return 0; + else + { + Kernel::Triangle_3 triangle( + f->halfedge()->vertex()->point(), + f->halfedge()->next()->vertex()->point(), + f->halfedge()->next()->next()->vertex()->point() + ); + Primitive primitive(triangle, f); + tree->insert(primitive); + } + } + this->setProperty(aabb_property_name, + QVariant::fromValue(tree)); + return tree; } + else return 0; + } } void delete_aabb_tree(Scene_polyhedron_item* item) @@ -91,38 +246,15 @@ void push_back_xyz(const TypeWithXYZ& t, vector.push_back(t.z()); } -typedef Polyhedron::Traits Traits; -typedef Polyhedron::Facet Facet; -typedef CGAL::Triangulation_2_projection_traits_3 P_traits; -typedef Polyhedron::Halfedge_handle Halfedge_handle; -struct Face_info { - Polyhedron::Halfedge_handle e[3]; - bool is_external; -}; -typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; -typedef CGAL::Triangulation_face_base_with_info_2 Fb1; -typedef CGAL::Constrained_triangulation_face_base_2 Fb; -typedef CGAL::Triangulation_data_structure_2 TDS; -typedef CGAL::No_intersection_tag Itag; -typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; -typedef CGAL::Constrained_triangulation_plus_2 CDT; //Make sure all the facets are triangles - -template +template void Scene_polyhedron_item::triangulate_facet(Facet_iterator fit, - const FaceNormalPmap& fnmap, + const Traits::Vector_3& normal, const VertexNormalPmap& vnmap, const bool colors_only) const { - //Computes the normal of the facet - Traits::Vector_3 normal = get(fnmap, fit); - //check if normal contains NaN values if (normal.x() != normal.x() || normal.y() != normal.y() || normal.z() != normal.z()) { @@ -408,11 +540,11 @@ Scene_polyhedron_item::compute_normals_and_vertices(const bool colors_only) cons { if (f == boost::graph_traits::null_face()) continue; - + Vector nf = get(nf_pmap, f); + f->plane() = Kernel::Plane_3(f->halfedge()->vertex()->point(), nf); if(is_triangle(f->halfedge(),*poly)) { const int this_patch_id = f->patch_id(); - Vector n = get(nf_pmap, f); HF_circulator he = f->facet_begin(); HF_circulator end = he; CGAL_For_all(he,end) @@ -427,7 +559,7 @@ Scene_polyhedron_item::compute_normals_and_vertices(const bool colors_only) cons continue; // If Flat shading:1 normal per polygon added once per vertex - push_back_xyz(n, normals_flat); + push_back_xyz(nf, normals_flat); //// If Gouraud shading: 1 normal per vertex Vector nv = get(nv_pmap, he->vertex()); @@ -454,8 +586,6 @@ Scene_polyhedron_item::compute_normals_and_vertices(const bool colors_only) cons if (colors_only) continue; - Vector nf = get(nf_pmap, f); - //1st half-quad Point p0 = f->halfedge()->vertex()->point(); Point p1 = f->halfedge()->next()->vertex()->point(); @@ -512,7 +642,7 @@ Scene_polyhedron_item::compute_normals_and_vertices(const bool colors_only) cons } else { - triangulate_facet(f, nf_pmap, nv_pmap, colors_only); + triangulate_facet(f, nf, nv_pmap, colors_only); } } @@ -576,6 +706,7 @@ Scene_polyhedron_item::Scene_polyhedron_item() nb_lines = 0; nb_f_lines = 0; invalidate_stats(); + init(); } Scene_polyhedron_item::Scene_polyhedron_item(Polyhedron* const p) @@ -1011,107 +1142,94 @@ Scene_polyhedron_item::select(double orig_x, double dir_y, double dir_z) { - if(facet_picking_m) { - typedef Input_facets_AABB_tree Tree; - typedef Tree::Object_and_primitive_id Object_and_primitive_id; + void* vertex_to_emit = 0; + if(facet_picking_m) { + typedef Input_facets_AABB_tree Tree; - Tree* aabb_tree = get_aabb_tree(this); - if(aabb_tree) { - const Kernel::Point_3 ray_origin(orig_x, orig_y, orig_z); - const Kernel::Vector_3 ray_dir(dir_x, dir_y, dir_z); - const Kernel::Ray_3 ray(ray_origin, ray_dir); - typedef std::list Intersections; - Intersections intersections; - aabb_tree->all_intersections(ray, std::back_inserter(intersections)); - Intersections::iterator closest = intersections.begin(); - if(closest != intersections.end()) { - const Kernel::Point_3* closest_point = - CGAL::object_cast(&closest->first); - for(Intersections::iterator - it = boost::next(intersections.begin()), - end = intersections.end(); - it != end; ++it) - { - if(! closest_point) { - closest = it; - } - else { - const Kernel::Point_3* it_point = - CGAL::object_cast(&it->first); - if(it_point && - (ray_dir * (*it_point - *closest_point)) < 0) - { - closest = it; - closest_point = it_point; - } - } - } - if(closest_point) { - Polyhedron::Facet_handle selected_fh = closest->second; - // The computation of the nearest vertex may be costly. Only - // do it if some objects are connected to the signal - // 'selected_vertex'. - if(QObject::receivers(SIGNAL(selected_vertex(void*))) > 0) - { - Polyhedron::Halfedge_around_facet_circulator - he_it = selected_fh->facet_begin(), - around_end = he_it; + Tree* aabb_tree = static_cast(get_aabb_tree()); + if(aabb_tree) { + const Kernel::Point_3 ray_origin(orig_x, orig_y, orig_z); + const Kernel::Vector_3 ray_dir(dir_x, dir_y, dir_z); + const Kernel::Ray_3 ray(ray_origin, ray_dir); + const boost::optional< Tree::Intersection_and_primitive_id::Type > + variant = aabb_tree->first_intersection(ray); + if(variant) + { + const Kernel::Point_3* closest_point = boost::get( &variant->first ); + if(closest_point) { + Polyhedron::Facet_handle selected_fh = variant->second; + // The computation of the nearest vertex may be costly. Only + // do it if some objects are connected to the signal + // 'selected_vertex'. + if(QObject::receivers(SIGNAL(selected_vertex(void*))) > 0) + { + Polyhedron::Halfedge_around_facet_circulator + he_it = selected_fh->facet_begin(), + around_end = he_it; - Polyhedron::Vertex_handle v = he_it->vertex(), nearest_v = v; + Polyhedron::Vertex_handle v = he_it->vertex(), nearest_v = v; - Kernel::FT sq_dist = CGAL::squared_distance(*closest_point, - v->point()); - while(++he_it != around_end) { - v = he_it->vertex(); - Kernel::FT new_sq_dist = CGAL::squared_distance(*closest_point, - v->point()); - if(new_sq_dist < sq_dist) { - sq_dist = new_sq_dist; - nearest_v = v; - } - } - //bottleneck - Q_EMIT selected_vertex((void*)(&*nearest_v)); - } + Kernel::FT sq_dist = CGAL::squared_distance(*closest_point, + v->point()); + while(++he_it != around_end) { + v = he_it->vertex(); + Kernel::FT new_sq_dist = CGAL::squared_distance(*closest_point, + v->point()); + if(new_sq_dist < sq_dist) { + sq_dist = new_sq_dist; + nearest_v = v; + } + } + vertex_to_emit = (void*)(&*nearest_v); + } - if(QObject::receivers(SIGNAL(selected_edge(void*))) > 0 + if(QObject::receivers(SIGNAL(selected_edge(void*))) > 0 || QObject::receivers(SIGNAL(selected_halfedge(void*))) > 0) - { - Polyhedron::Halfedge_around_facet_circulator - he_it = selected_fh->facet_begin(), - around_end = he_it; + { + Polyhedron::Halfedge_around_facet_circulator + he_it = selected_fh->facet_begin(), + around_end = he_it; - Polyhedron::Halfedge_handle nearest_h = he_it; - Kernel::FT sq_dist = CGAL::squared_distance(*closest_point, - Kernel::Segment_3(he_it->vertex()->point(), he_it->opposite()->vertex()->point())); + Polyhedron::Halfedge_handle nearest_h = he_it; + Kernel::FT sq_dist = CGAL::squared_distance(*closest_point, + Kernel::Segment_3(he_it->vertex()->point(), + he_it->opposite()-> + vertex()-> + point())); - while(++he_it != around_end) { - Kernel::FT new_sq_dist = CGAL::squared_distance(*closest_point, - Kernel::Segment_3(he_it->vertex()->point(), he_it->opposite()->vertex()->point())); - if(new_sq_dist < sq_dist) { - sq_dist = new_sq_dist; - nearest_h = he_it; - } - } + while(++he_it != around_end) + { + Kernel::FT new_sq_dist = CGAL::squared_distance(*closest_point, + Kernel::Segment_3(he_it->vertex()->point(), + he_it->opposite()-> + vertex()-> + point())); + if(new_sq_dist < sq_dist) { + sq_dist = new_sq_dist; + nearest_h = he_it; + } + } Q_EMIT selected_halfedge((void*)(&*nearest_h)); Q_EMIT selected_edge((void*)(std::min)(&*nearest_h, &*nearest_h->opposite())); - } - + } + Q_EMIT selected_vertex(vertex_to_emit); Q_EMIT selected_facet((void*)(&*selected_fh)); - if(erase_next_picked_facet_m) { - polyhedron()->erase_facet(selected_fh->halfedge()); - polyhedron()->normalize_border(); - //set_erase_next_picked_facet(false); - invalidateOpenGLBuffers(); + + if(erase_next_picked_facet_m) { + polyhedron()->erase_facet(selected_fh->halfedge()); + polyhedron()->normalize_border(); + //set_erase_next_picked_facet(false); + invalidateOpenGLBuffers(); Q_EMIT itemChanged(); - } - } - } + } } + } } - Base::select(orig_x, orig_y, orig_z, dir_x, dir_y, dir_z); + } + Base::select(orig_x, orig_y, orig_z, dir_x, dir_y, dir_z); + Q_EMIT selection_done(); } void Scene_polyhedron_item::update_vertex_indices() diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h index c09c6146900..2dde2520e3a 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h @@ -109,13 +109,13 @@ public Q_SLOTS: double dir_x, double dir_y, double dir_z); - void update_vertex_indices(); void update_facet_indices(); void update_halfedge_indices(); void invalidate_aabb_tree(); Q_SIGNALS: + void selection_done(); void selected_vertex(void*); void selected_facet(void*); void selected_edge(void*); @@ -149,7 +149,7 @@ private: Edges, Feature_edges, Gouraud_Facets, - NbOfVaos = Gouraud_Facets+1 + NbOfVaos }; enum VBOs { Facets_vertices = 0, @@ -159,7 +159,7 @@ private: Feature_edges_vertices, Edges_color, Facets_normals_gouraud, - NbOfVbos = Facets_normals_gouraud+1 + NbOfVbos }; mutable std::vector positions_lines; @@ -180,10 +180,11 @@ private: using CGAL::Three::Scene_item::initializeBuffers; void initializeBuffers(CGAL::Three::Viewer_interface *viewer = 0) const; void compute_normals_and_vertices(const bool colors_only = false) const; - template + template void triangulate_facet(Facet_iterator, - const FaceNormalPmap&, const VertexNormalPmap&, + const Polyhedron::Traits::Vector_3&, const VertexNormalPmap&, const bool colors_only) const; + void* get_aabb_tree(); double volume, area; int m_min_patch_id; // the min value of the patch ids initialized in init() diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h index e277792e801..b727d813baf 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h @@ -43,21 +43,24 @@ public: Scene_polyhedron_item_k_ring_selection (Scene_polyhedron_item* poly_item, QMainWindow* mw, Active_handle::Type aht, int k_ring) - :is_active(false) + :is_active(false), is_edit_mode(false) { init(poly_item, mw, aht, k_ring); } - void init(Scene_polyhedron_item* poly_item, QMainWindow* /*mw*/, Active_handle::Type aht, int k_ring) { + void setEditMode(bool b) { is_edit_mode = b; } + + void init(Scene_polyhedron_item* poly_item, QMainWindow* mw, Active_handle::Type aht, int k_ring) { this->poly_item = poly_item; this->active_handle_type = aht; this->k_ring = k_ring; - + mainwindow = mw; poly_item->enable_facets_picking(true); poly_item->set_color_vector_read_only(true); QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); viewer->installEventFilter(this); + mw->installEventFilter(this); #if QGLVIEWER_VERSION >= 0x020501 viewer->setMouseBindingDescription(Qt::Key_D, Qt::ShiftModifier, Qt::LeftButton, "(When in selection plugin) Removes the clicked primitive from the selection. "); #else @@ -73,8 +76,9 @@ public Q_SLOTS: void vertex_has_been_selected(void* void_ptr) { is_active=true; - if(active_handle_type != Active_handle::VERTEX) { return; } - process_selection( static_cast(void_ptr)->halfedge()->vertex() ); + if(active_handle_type == Active_handle::VERTEX) + process_selection( static_cast(void_ptr)->halfedge()->vertex() ); + updateIsTreated(); } void facet_has_been_selected(void* void_ptr) { @@ -82,23 +86,37 @@ public Q_SLOTS: if (active_handle_type == Active_handle::FACET || active_handle_type == Active_handle::CONNECTED_COMPONENT) process_selection(static_cast(void_ptr)->halfedge()->facet()); + updateIsTreated(); } void edge_has_been_selected(void* void_ptr) { is_active=true; - if(active_handle_type != Active_handle::EDGE) { return; } - process_selection( edge(static_cast(void_ptr)->opposite()->opposite(), *poly_item->polyhedron()) ); + if(active_handle_type == Active_handle::EDGE) + process_selection( edge(static_cast(void_ptr)->opposite()->opposite(), *poly_item->polyhedron()) ); + updateIsTreated(); } + Q_SIGNALS: void selected(const std::set&); void selected(const std::set&); void selected(const std::set&); void toogle_insert(const bool); void endSelection(); + void resetIsTreated(); protected: + void updateIsTreated() + { + static ushort i = 0; + i++; + if(i==3) + { + i = 0; + Q_EMIT resetIsTreated(); + } + } template void process_selection(HandleType clicked) { const std::set& selection = extract_k_ring(clicked, k_ring); @@ -169,9 +187,10 @@ protected: } - bool eventFilter(QObject* /*target*/, QEvent *event) + bool eventFilter(QObject* target, QEvent *event) { // This filter is both filtering events from 'viewer' and 'main window' + // key events if(event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { QKeyEvent *keyEvent = static_cast(event); @@ -193,6 +212,12 @@ protected: } // mouse events if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) { + if(!state.shift_pressing && target == mainwindow) + { + QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); + viewer->setFocus(); + return false; + } QMouseEvent* mouse_event = static_cast(event); if(mouse_event->button() == Qt::LeftButton) { state.left_button_pressing = event->type() == QEvent::MouseButtonPress; @@ -205,16 +230,22 @@ protected: } //to avoid the contextual menu to mess up the states. else if(mouse_event->button() == Qt::RightButton) { - state.left_button_pressing = false; - state.shift_pressing = false; - } + state.left_button_pressing = false; + state.shift_pressing = false; + } } - // use mouse move event for paint-like selection - if( (event->type() == QEvent::MouseMove - || (event->type() == QEvent::MouseButtonPress - && static_cast(event)->button() == Qt::LeftButton)) - && (state.shift_pressing && state.left_button_pressing) ) + + // if not in edit mode, use mouse move event for paint-like selection + if( (!is_edit_mode && event->type() == QEvent::MouseMove && state.shift_pressing && state.left_button_pressing) + || + (event->type() == QEvent::MouseButtonPress && static_cast(event)->button() == Qt::LeftButton && state.shift_pressing )) { + if(target == mainwindow) + { + QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); + viewer->setFocus(); + return false; + } // paint with mouse move event QMouseEvent* mouse_event = static_cast(event); QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); @@ -231,6 +262,9 @@ protected: }//end MouseMove return false; } + + bool is_edit_mode; + QMainWindow *mainwindow; }; #endif diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp index b7fa5e5147c..fd693392d87 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp @@ -1,169 +1,456 @@ #include "Scene_polyhedron_selection_item.h" #include +#include +#include +#include +#include +#include +#include +#include + void Scene_polyhedron_selection_item::initializeBuffers(CGAL::Three::Viewer_interface *viewer)const { - //vao containing the data for the unselected facets - { - program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer); - program->bind(); + //vao containing the data for the facets + { + program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer); + program->bind(); - vaos[0]->bind(); - buffers[0].bind(); - buffers[0].allocate(positions_facets.data(), - static_cast(positions_facets.size()*sizeof(float))); - program->enableAttributeArray("vertex"); - program->setAttributeBuffer("vertex",GL_FLOAT,0,3); - buffers[0].release(); + vaos[0]->bind(); + buffers[0].bind(); + buffers[0].allocate(positions_facets.data(), + static_cast(positions_facets.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[0].release(); - buffers[1].bind(); - buffers[1].allocate(normals.data(), - static_cast(normals.size()*sizeof(float))); - program->enableAttributeArray("normals"); - program->setAttributeBuffer("normals",GL_FLOAT,0,3); - buffers[1].release(); + buffers[1].bind(); + buffers[1].allocate(normals.data(), + static_cast(normals.size()*sizeof(float))); + program->enableAttributeArray("normals"); + program->setAttributeBuffer("normals",GL_FLOAT,0,3); + buffers[1].release(); - vaos[0]->release(); - program->release(); + vaos[0]->release(); + program->release(); - } - //vao containing the data for the unselected lines - { - program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); - program->bind(); - vaos[1]->bind(); + } + //vao containing the data for the lines + { + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + program->bind(); + vaos[1]->bind(); - buffers[2].bind(); - buffers[2].allocate(positions_lines.data(), - static_cast(positions_lines.size()*sizeof(float))); - program->enableAttributeArray("vertex"); - program->setAttributeBuffer("vertex",GL_FLOAT,0,3); - buffers[2].release(); + buffers[2].bind(); + buffers[2].allocate(positions_lines.data(), + static_cast(positions_lines.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[2].release(); - program->release(); + program->release(); - vaos[1]->release(); + vaos[1]->release(); - } - //vao containing the data for the points - { - program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); - program->bind(); - vaos[2]->bind(); + } + //vao containing the data for the points + { + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + program->bind(); + vaos[2]->bind(); - buffers[3].bind(); - buffers[3].allocate(positions_points.data(), - static_cast(positions_points.size()*sizeof(float))); - program->enableAttributeArray("vertex"); - program->setAttributeBuffer("vertex",GL_FLOAT,0,3); - buffers[3].release(); + buffers[3].bind(); + buffers[3].allocate(positions_points.data(), + static_cast(positions_points.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[3].release(); + program->release(); - buffers[6].release(); - program->release(); + vaos[2]->release(); + } - vaos[2]->release(); - } - nb_facets = positions_facets.size(); - positions_facets.resize(0); - std::vector(positions_facets).swap(positions_facets); + nb_facets = positions_facets.size(); + positions_facets.resize(0); + std::vector(positions_facets).swap(positions_facets); - normals.resize(0); - std::vector(normals).swap(normals); + normals.resize(0); + std::vector(normals).swap(normals); - nb_lines = positions_lines.size(); - positions_lines.resize(0); - std::vector(positions_lines).swap(positions_lines); + nb_lines = positions_lines.size(); + positions_lines.resize(0); + std::vector(positions_lines).swap(positions_lines); - nb_points = positions_points.size(); - positions_points.resize(0); - std::vector(positions_points).swap(positions_points); + nb_points = positions_points.size(); + positions_points.resize(0); + std::vector(positions_points).swap(positions_points); - are_buffers_filled = true; + + + are_buffers_filled = true; } -void Scene_polyhedron_selection_item::computeElements()const +void Scene_polyhedron_selection_item::initialize_temp_buffers(CGAL::Three::Viewer_interface *viewer)const { - positions_facets.clear(); - positions_lines.clear(); - positions_points.clear(); - normals.clear(); - //The facets + //vao containing the data for the temp facets + { + program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer); + program->bind(); + + vaos[3]->bind(); + buffers[4].bind(); + buffers[4].allocate(positions_temp_facets.data(), + static_cast(positions_temp_facets.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[4].release(); + + + + buffers[5].bind(); + buffers[5].allocate(temp_normals.data(), + static_cast(temp_normals.size()*sizeof(float))); + program->enableAttributeArray("normals"); + program->setAttributeBuffer("normals",GL_FLOAT,0,3); + buffers[5].release(); + + vaos[3]->release(); + program->release(); + + } + //vao containing the data for the temp lines + { + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + program->bind(); + vaos[4]->bind(); + + buffers[6].bind(); + buffers[6].allocate(positions_temp_lines.data(), + static_cast(positions_temp_lines.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[6].release(); + + program->release(); + + vaos[4]->release(); + + } + //vao containing the data for the temp points + { + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + program->bind(); + vaos[5]->bind(); + + buffers[7].bind(); + buffers[7].allocate(positions_temp_points.data(), + static_cast(positions_temp_points.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[7].release(); + + program->release(); + + vaos[5]->release(); + } + nb_temp_facets = positions_temp_facets.size(); + positions_temp_facets.resize(0); + std::vector(positions_temp_facets).swap(positions_temp_facets); + + temp_normals.resize(0); + std::vector(temp_normals).swap(temp_normals); + + nb_temp_lines = positions_temp_lines.size(); + positions_temp_lines.resize(0); + std::vector(positions_temp_lines).swap(positions_temp_lines); + + nb_temp_points = positions_temp_points.size(); + positions_temp_points.resize(0); + std::vector(positions_temp_points).swap(positions_temp_points); + + are_temp_buffers_filled = true; +} + +template +void push_back_xyz(const TypeWithXYZ& t, + ContainerWithPushBack& vector) +{ + vector.push_back(t.x()); + vector.push_back(t.y()); + vector.push_back(t.z()); +} + +typedef Polyhedron::Traits Traits; +typedef Polyhedron::Facet Facet; +typedef CGAL::Triangulation_2_projection_traits_3 P_traits; +typedef Polyhedron::Halfedge_handle Halfedge_handle; +struct Face_info { + Polyhedron::Halfedge_handle e[3]; + bool is_external; +}; +typedef CGAL::Triangulation_vertex_base_with_info_2 Vb; +typedef CGAL::Triangulation_face_base_with_info_2 Fb1; +typedef CGAL::Constrained_triangulation_face_base_2 Fb; +typedef CGAL::Triangulation_data_structure_2 TDS; +typedef CGAL::Exact_predicates_tag Itag; +typedef CGAL::Constrained_Delaunay_triangulation_2 CDTbase; +typedef CGAL::Constrained_triangulation_plus_2 CDT; + +//Make sure all the facets are triangles +typedef Polyhedron::Traits Kernel; +typedef Kernel::Point_3 Point; +typedef Kernel::Vector_3 Vector; +typedef Polyhedron::Facet_iterator Facet_iterator; +typedef Polyhedron::Halfedge_around_facet_circulator HF_circulator; +typedef boost::graph_traits::face_descriptor face_descriptor; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + + +template +void +Scene_polyhedron_selection_item::triangulate_facet(Facet_handle fit,const FaceNormalPmap& fnmap, + std::vector &p_facets,std::vector &p_normals ) const +{ + //Computes the normal of the facet + Traits::Vector_3 normal = get(fnmap, fit); + + //check if normal contains NaN values + if (normal.x() != normal.x() || normal.y() != normal.y() || normal.z() != normal.z()) { + qDebug()<<"Warning : normal is not valid. Facet not displayed"; + return; + } + P_traits cdt_traits(normal); + CDT cdt(cdt_traits); + Facet::Halfedge_around_facet_circulator + he_circ = fit->facet_begin(), + he_circ_end(he_circ); - for(Selection_set_facet::iterator - it = selected_facets.begin(), - end = selected_facets.end(); - it != end; ++it) - { - const Kernel::Vector_3 n = - CGAL::Polygon_mesh_processing::compute_face_normal(*it, *this->poly_item->polyhedron()); - - normals.push_back(n.x()); - normals.push_back(n.y()); - normals.push_back(n.z()); - - normals.push_back(n.x()); - normals.push_back(n.y()); - normals.push_back(n.z()); - - normals.push_back(n.x()); - normals.push_back(n.y()); - normals.push_back(n.z()); - - - Polyhedron::Halfedge_around_facet_circulator - he = (*it)->facet_begin(), - cend = he; - - CGAL_For_all(he,cend) + // Iterates on the vector of facet handles + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + boost::container::flat_map v2v; + CDT::Vertex_handle previous, first; + do { + CDT::Vertex_handle vh = cdt.insert(he_circ->vertex()->point()); + v2v.insert(std::make_pair(vh, he_circ->vertex())); + if(first == 0) { + first = vh; + } + vh->info() = he_circ; + if(previous != 0 && previous != vh) { + cdt.insert_constraint(previous, vh); + } + previous = vh; + } while( ++he_circ != he_circ_end ); + cdt.insert_constraint(previous, first); + // sets mark is_external + for(CDT::All_faces_iterator + fit2 = cdt.all_faces_begin(), + end = cdt.all_faces_end(); + fit2 != end; ++fit2) + { + fit2->info().is_external = false; + } + //check if the facet is external or internal + std::queue face_queue; + face_queue.push(cdt.infinite_vertex()->face()); + while(! face_queue.empty() ) { + CDT::Face_handle fh = face_queue.front(); + face_queue.pop(); + if(fh->info().is_external) continue; + fh->info().is_external = true; + for(int i = 0; i <3; ++i) { + if(!cdt.is_constrained(std::make_pair(fh, i))) { - const Kernel::Point_3& p = he->vertex()->point(); - positions_facets.push_back(p.x()); - positions_facets.push_back(p.y()); - positions_facets.push_back(p.z()); + face_queue.push(fh->neighbor(i)); } } } + //iterates on the internal faces to add the vertices to the positions + //and the normals to the appropriate vectors + for(CDT::Finite_faces_iterator + ffit = cdt.finite_faces_begin(), + end = cdt.finite_faces_end(); + ffit != end; ++ffit) + { + if(ffit->info().is_external) + continue; + + push_back_xyz(ffit->vertex(0)->point(), p_facets); + push_back_xyz(ffit->vertex(1)->point(), p_facets); + push_back_xyz(ffit->vertex(2)->point(), p_facets); + + push_back_xyz(normal, p_normals); + push_back_xyz(normal, p_normals); + push_back_xyz(normal, p_normals); + } +} + + +void Scene_polyhedron_selection_item::compute_any_elements(std::vector& p_facets, std::vector& p_lines, std::vector& p_points, std::vector& p_normals, + const Selection_set_vertex& p_sel_vertices, const Selection_set_facet& p_sel_facets, const Selection_set_edge& p_sel_edges)const +{ + p_facets.clear(); + p_lines.clear(); + p_points.clear(); + p_normals.clear(); + //The facet + boost::container::flat_map face_normals_map; + boost::associative_property_map< boost::container::flat_map > + nf_pmap(face_normals_map); + boost::container::flat_map vertex_normals_map; + boost::associative_property_map< boost::container::flat_map > + nv_pmap(vertex_normals_map); +if(!poly) + return; + PMP::compute_normals(*poly, nv_pmap, nf_pmap); + for(Selection_set_facet::iterator + it = p_sel_facets.begin(), + end = p_sel_facets.end(); + it != end; it++) + { + Facet_handle f = (*it); + if (f == boost::graph_traits::null_face()) + continue; + + if(is_triangle(f->halfedge(),*poly)) + { + const Kernel::Vector_3 n = + CGAL::Polygon_mesh_processing::compute_face_normal(f, *this->poly_item->polyhedron()); + + p_normals.push_back(n.x()); + p_normals.push_back(n.y()); + p_normals.push_back(n.z()); + + p_normals.push_back(n.x()); + p_normals.push_back(n.y()); + p_normals.push_back(n.z()); + + p_normals.push_back(n.x()); + p_normals.push_back(n.y()); + p_normals.push_back(n.z()); + + + Polyhedron::Halfedge_around_facet_circulator + he = f->facet_begin(), + cend = he; + + CGAL_For_all(he,cend) + { + const Kernel::Point_3& p = he->vertex()->point(); + p_facets.push_back(p.x()); + p_facets.push_back(p.y()); + p_facets.push_back(p.z()); + } + } + else if (is_quad(f->halfedge(), *poly)) + { + Vector nf = get(nf_pmap, f); + + //1st half-quad + Point p0 = f->halfedge()->vertex()->point(); + Point p1 = f->halfedge()->next()->vertex()->point(); + Point p2 = f->halfedge()->next()->next()->vertex()->point(); + + push_back_xyz(p0, p_facets); + push_back_xyz(p1, p_facets); + push_back_xyz(p2, p_facets); + + push_back_xyz(nf, p_normals); + push_back_xyz(nf, p_normals); + push_back_xyz(nf, p_normals); + + //2nd half-quad + p0 = f->halfedge()->next()->next()->vertex()->point(); + p1 = f->halfedge()->prev()->vertex()->point(); + p2 = f->halfedge()->vertex()->point(); + + push_back_xyz(p0, p_facets); + push_back_xyz(p1, p_facets); + push_back_xyz(p2, p_facets); + + push_back_xyz(nf, p_normals); + push_back_xyz(nf, p_normals); + push_back_xyz(nf, p_normals); + } + else + { + triangulate_facet(f, nf_pmap, p_facets, p_normals); + } + } //The Lines { - for(Selection_set_edge::iterator it = selected_edges.begin(); it != selected_edges.end(); ++it) { + for(Selection_set_edge::iterator it = p_sel_edges.begin(); it != p_sel_edges.end(); ++it) { const Kernel::Point_3& a = (it->halfedge())->vertex()->point(); const Kernel::Point_3& b = (it->halfedge())->opposite()->vertex()->point(); - positions_lines.push_back(a.x()); - positions_lines.push_back(a.y()); - positions_lines.push_back(a.z()); + p_lines.push_back(a.x()); + p_lines.push_back(a.y()); + p_lines.push_back(a.z()); - positions_lines.push_back(b.x()); - positions_lines.push_back(b.y()); - positions_lines.push_back(b.z()); + p_lines.push_back(b.x()); + p_lines.push_back(b.y()); + p_lines.push_back(b.z()); } } - //The points { for(Selection_set_vertex::iterator - it = selected_vertices.begin(), - end = selected_vertices.end(); + it = p_sel_vertices.begin(), + end = p_sel_vertices.end(); it != end; ++it) { const Kernel::Point_3& p = (*it)->point(); - positions_points.push_back(p.x()); - positions_points.push_back(p.y()); - positions_points.push_back(p.z()); + p_points.push_back(p.x()); + p_points.push_back(p.y()); + p_points.push_back(p.z()); } } } +void Scene_polyhedron_selection_item::computeElements()const +{ + compute_any_elements(positions_facets, positions_lines, positions_points, normals, + selected_vertices, selected_facets, selected_edges); +} +void Scene_polyhedron_selection_item::compute_temp_elements()const +{ + compute_any_elements(positions_temp_facets, positions_temp_lines, positions_temp_points, temp_normals, + temp_selected_vertices, temp_selected_facets, temp_selected_edges); +} void Scene_polyhedron_selection_item::draw(CGAL::Three::Viewer_interface* viewer) const { + GLfloat offset_factor; + GLfloat offset_units; + if(!are_temp_buffers_filled) + { + compute_temp_elements(); + initialize_temp_buffers(viewer); + } + + viewer->glGetFloatv( GL_POLYGON_OFFSET_FACTOR, &offset_factor); + viewer->glGetFloatv(GL_POLYGON_OFFSET_UNITS, &offset_units); + glPolygonOffset(-1.f, 1.f); + vaos[3]->bind(); + program = getShaderProgram(PROGRAM_WITH_LIGHT); + attribBuffers(viewer,PROGRAM_WITH_LIGHT); + program->bind(); + program->setAttributeValue("colors",QColor(0,255,0)); + viewer->glDrawArrays(GL_TRIANGLES, 0, static_cast(nb_temp_facets/3)); + program->release(); + vaos[3]->release(); + glPolygonOffset(offset_factor, offset_units); if(!are_buffers_filled) { computeElements(); @@ -171,8 +458,6 @@ void Scene_polyhedron_selection_item::draw(CGAL::Three::Viewer_interface* viewer } drawPoints(viewer); - GLfloat offset_factor; - GLfloat offset_units; viewer->glGetFloatv( GL_POLYGON_OFFSET_FACTOR, &offset_factor); viewer->glGetFloatv(GL_POLYGON_OFFSET_UNITS, &offset_units); glPolygonOffset(-1.f, 1.f); @@ -188,50 +473,84 @@ void Scene_polyhedron_selection_item::draw(CGAL::Three::Viewer_interface* viewer glPolygonOffset(offset_factor, offset_units); drawEdges(viewer); - } void Scene_polyhedron_selection_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const { - if(!are_buffers_filled) - { - computeElements(); - initializeBuffers(viewer); - } - viewer->glLineWidth(3.f); - vaos[1]->bind(); - program = getShaderProgram(PROGRAM_NO_SELECTION); - attribBuffers(viewer,PROGRAM_NO_SELECTION); - program->bind(); + viewer->glLineWidth(2.0f); + if(!are_temp_buffers_filled) + { + compute_temp_elements(); + initialize_temp_buffers(viewer); + } - program->setAttributeValue("colors",edge_color); - viewer->glDrawArrays(GL_LINES, 0, static_cast(nb_lines/3)); - program->release(); - vaos[1]->release(); - viewer->glLineWidth(1.f); + vaos[4]->bind(); + program = getShaderProgram(PROGRAM_NO_SELECTION); + attribBuffers(viewer,PROGRAM_NO_SELECTION); + program->bind(); + + program->setAttributeValue("colors",QColor(0,200,0)); + viewer->glDrawArrays(GL_LINES, 0, static_cast(nb_temp_lines/3)); + program->release(); + vaos[4]->release(); + viewer->glLineWidth(3.0f); + if(!are_buffers_filled) + { + computeElements(); + initializeBuffers(viewer); + } + + vaos[1]->bind(); + program = getShaderProgram(PROGRAM_NO_SELECTION); + attribBuffers(viewer,PROGRAM_NO_SELECTION); + program->bind(); + + program->setAttributeValue("colors",edge_color); + viewer->glDrawArrays(GL_LINES, 0, static_cast(nb_lines/3)); + program->release(); + vaos[1]->release(); + + + viewer->glLineWidth(1.f); } void Scene_polyhedron_selection_item::drawPoints(CGAL::Three::Viewer_interface* viewer) const { - if(!are_buffers_filled) - { - computeElements(); - initializeBuffers(viewer); - } - viewer->glPointSize(5.f); - vaos[2]->bind(); - program = getShaderProgram(PROGRAM_NO_SELECTION); - attribBuffers(viewer,PROGRAM_NO_SELECTION); - program->bind(); - program->setAttributeValue("colors",vertex_color); - viewer->glDrawArrays(GL_POINTS, 0, static_cast(nb_points/3)); - program->release(); - vaos[2]->release(); - viewer->glPointSize(1.f); + if(!are_temp_buffers_filled) + { + compute_temp_elements(); + initialize_temp_buffers(viewer); + } + vaos[5]->bind(); + program = getShaderProgram(PROGRAM_NO_SELECTION); + attribBuffers(viewer,PROGRAM_NO_SELECTION); + program->bind(); + program->setAttributeValue("colors",QColor(0,50,0)); + viewer->glDrawArrays(GL_POINTS, 0, static_cast(nb_temp_points/3)); + program->release(); + vaos[5]->release(); + + viewer->glPointSize(5.5f); + if(!are_buffers_filled) + { + computeElements(); + initializeBuffers(viewer); + } + vaos[2]->bind(); + program = getShaderProgram(PROGRAM_NO_SELECTION); + attribBuffers(viewer,PROGRAM_NO_SELECTION); + program->bind(); + program->setAttributeValue("colors",vertex_color); + viewer->glDrawArrays(GL_POINTS, 0, static_cast(nb_points/3)); + program->release(); + vaos[2]->release(); + + viewer->glPointSize(1.f); } + void Scene_polyhedron_selection_item::inverse_selection() { switch(k_ring_selector.active_handle_type) @@ -267,3 +586,792 @@ void Scene_polyhedron_selection_item::inverse_selection() QGLViewer* v = *QGLViewer::QGLViewerPool().begin(); v->update(); } + +void Scene_polyhedron_selection_item::set_operation_mode(int mode) +{ + k_ring_selector.setEditMode(true); + Q_EMIT updateInstructions(QString("SHIFT + left click to apply operation.")); + switch(mode) + { + case -1: + //restore original selection_type + set_active_handle_type(original_sel_mode); + k_ring_selector.setEditMode(false); + break; + //Join vertex + case 0: + Q_EMIT updateInstructions("Select the edge with extremities you want to join. (1/2)"); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + //Split vertex + case 1: + Q_EMIT updateInstructions("Select the vertex you want to split. (1/3)"); + //set the selection type to Vertex + set_active_handle_type(static_cast(0)); + break; + //Split edge + case 2: + Q_EMIT updateInstructions("Select the edge you want to split."); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + //Join face + case 3: + Q_EMIT updateInstructions("Select the edge separating the faces you want to join."); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + //Split face + case 4: + Q_EMIT updateInstructions("Select the facet you want to split (degree >= 4). (1/3)"); + //set the selection type to Facet + set_active_handle_type(static_cast(1)); + break; + //Collapse edge + case 5: + Q_EMIT updateInstructions("Select the edge you want to collapse."); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + //Flip edge + case 6: + Q_EMIT updateInstructions("Select the edge you want to flip."); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + //Add center vertex + case 7: + Q_EMIT updateInstructions("Select a facet."); + //set the selection type to Facet + set_active_handle_type(static_cast(1)); + break; + //Remove center vertex + case 8: + Q_EMIT updateInstructions("Select the vertex you want to remove."); + //set the selection type to vertex + set_active_handle_type(static_cast(0)); + break; + //Add vertex and face to border + case 9: + Q_EMIT updateInstructions("Select a border edge. (1/2)"); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + //Add face to border + case 10: + Q_EMIT updateInstructions("Select a border edge. (1/2)"); + //set the selection type to Edge + set_active_handle_type(static_cast(2)); + break; + default: + break; + } + operation_mode = mode; +} +template +bool Scene_polyhedron_selection_item::treat_classic_selection(const HandleRange& selection) +{ + typedef typename HandleRange::value_type HandleType; + Selection_traits tr(this); + bool any_change = false; + if(is_insert) { + BOOST_FOREACH(HandleType h, selection) + any_change |= tr.container().insert(h).second; + } + else{ + BOOST_FOREACH(HandleType h, selection) + any_change |= (tr.container().erase(h)!=0); + } + if(any_change) { invalidateOpenGLBuffers(); Q_EMIT itemChanged(); } + return any_change; +} + +bool Scene_polyhedron_selection_item::treat_selection(const std::set& selection) +{ + if(!is_treated) + { + Vertex_handle vh = *selection.begin(); + Selection_traits tr(this); + switch(operation_mode) + { + //classic selection + case -1: + { + return treat_classic_selection(selection); + break; + } + //Join vertex + case 0: + { + bool belong = false; + Halfedge_handle target = halfedge(to_join_ed, *polyhedron()); + if(halfedge(to_join_ed, *polyhedron())->vertex() == vh) + belong = true; + if(halfedge(to_join_ed, *polyhedron())->opposite()->vertex() == vh) + { + belong = true; + target = halfedge(to_join_ed, *polyhedron())->opposite(); + } + if(!belong) + { + tempInstructions("Vertices not joined : the vertex must belong to the selected edge.", + "Select the vertex that will remain. (2/2)"); + } + else + { + + polyhedron()->join_vertex(target); + + temp_selected_edges.clear(); + //set to select edge + set_active_handle_type(static_cast(2)); + tempInstructions("Vertices joined.", + "Select the edge with extremities you want to join. (1/2)"); + invalidateOpenGLBuffers(); + polyhedron_item()->invalidateOpenGLBuffers(); + } + break; + } + //Split vertex + case 1: + { + //save VH + to_split_vh = vh; + temp_selected_vertices.insert(to_split_vh); + //set to select facet + set_active_handle_type(static_cast(1)); + invalidateOpenGLBuffers(); + Q_EMIT updateInstructions("Select first facet. (2/3)"); + break; + } + //Split face + case 4: + { + static Vertex_handle s; + static Polyhedron::Halfedge_handle h1,h2; + static bool found_h1(false), found_h2(false); + if(!first_selected) + { + //Is the vertex on the face ? + Polyhedron::Halfedge_around_facet_circulator hafc = to_split_fh->facet_begin(); + Polyhedron::Halfedge_around_facet_circulator end = hafc; + CGAL_For_all(hafc, end) + { + if(hafc->vertex()==vh) + { + h1 = hafc; + s = vh; + found_h1 = true; + break; + } + } + if(!found_h1) + { + tempInstructions("Vertex not selected : The vertex is not on the face.", + "Select the first vertex. (2/3)"); + } + else + { + first_selected = true; + temp_selected_vertices.insert(s); + invalidateOpenGLBuffers(); + Q_EMIT updateInstructions("Select the second vertex (3/3)"); + } + } + else + { + bool is_same(false), are_next(false); + Polyhedron::Halfedge_around_facet_circulator hafc = to_split_fh->facet_begin(); + Polyhedron::Halfedge_around_facet_circulator end = hafc; + for(int i=0; i<1; i++) //seems useless but allow the use of break. + { + //Is the vertex on the face ? + CGAL_For_all(hafc, end) + + if(hafc->vertex()==vh) + { + h2 = hafc; + found_h2 = true; + break; + } + if(!found_h2) + { + break; + } + //Are they different ? + if(h1 == h2) + { + is_same = true; + break; + } + is_same = false; + //Are they directly following each other? + if(next(h1, *polyhedron()) == h2 || + next(h2, *polyhedron()) == h1) + { + are_next = true; + break; + } + are_next = false; + } + if(!found_h2) + tempInstructions("Vertex not selected : The vertex is not on the face.", + "Select the second vertex (3/3)."); + else if(is_same) + tempInstructions("Vertex not selected : The vertices must be different.", + "Select the second vertex (3/3)."); + else if(are_next) + tempInstructions("Vertex not selected : The vertices must not directly follow each other.", + "Select the second vertex (3/3)."); + else + { + CGAL::Euler::split_face(h1,h2, *polyhedron()); + first_selected = false; + temp_selected_vertices.clear(); + temp_selected_facets.clear(); + invalidateOpenGLBuffers(); + //reset selection type to Facet + set_active_handle_type(static_cast(1)); + tempInstructions("Face split.", + "Select a facet (1/3)."); + polyhedron_item()->invalidateOpenGLBuffers(); + } + } + break; + } + //Remove center vertex + case 8: + + bool has_hole = false; + Polyhedron::Halfedge_around_vertex_circulator hc = vh->vertex_begin(); + Polyhedron::Halfedge_around_vertex_circulator end(hc); + CGAL_For_all(hc, end) + { + if(hc->is_border()) + { + has_hole = true; + break; + } + } + if(!has_hole) + { + CGAL::Euler::remove_center_vertex(vh->halfedge(),*polyhedron()); + polyhedron_item()->invalidateOpenGLBuffers(); + } + else + { + tempInstructions("Vertex not selected : There must be no hole incident to the selection.", + "Select the vertex you want to remove."); + } + break; + + } + } + is_treated = true; + return false; +} + +//returns true if halfedge's facet's degree >= degree + +int facet_degree(Halfedge_handle h) +{ + if(h->is_border()) + { + Halfedge_handle it = h; + int deg =0; + do + { + deg ++; + it=it->next(); + } + while(it != h); + return deg; + } + else + return h->facet()->facet_degree(); +} + +bool Scene_polyhedron_selection_item:: treat_selection(const std::set& selection) +{ + edge_descriptor ed = *selection.begin(); + if(!is_treated) + { + Selection_traits tr(this); + switch(operation_mode) + { + //classic selection + case -1: + { + return treat_classic_selection(selection); + break; + } + //Join vertex + case 0: + if(facet_degree(halfedge(ed, *polyhedron())) < 4 + || + facet_degree(halfedge(ed, *polyhedron())->opposite())< 4) + { + tempInstructions("Edge not selected: the incident facets must have a degree of at least 4.", + "Select the edge with extremities you want to join.(1/2)"); + } + else + { + to_join_ed = ed; + temp_selected_edges.insert(to_join_ed); + invalidateOpenGLBuffers(); + //set to select vertex + set_active_handle_type(static_cast(0)); + Q_EMIT updateInstructions("Select the vertex that will remain."); + } + break; + //Split edge + case 2: + { + Polyhedron::Point_3 a(halfedge(ed, *polyhedron())->vertex()->point()),b(halfedge(ed, *polyhedron())->opposite()->vertex()->point()); + Polyhedron::Halfedge_handle hhandle = polyhedron()->split_edge(halfedge(ed, *polyhedron())); + Polyhedron::Point_3 p((b.x()+a.x())/2.0, (b.y()+a.y())/2.0,(b.z()+a.z())/2.0); + + hhandle->vertex()->point() = p; + selected_vertices.insert(hhandle->vertex()); + invalidateOpenGLBuffers(); + poly_item->invalidateOpenGLBuffers(); + tempInstructions("Edge splitted.", + "Select the edge you want to split."); + break; + } + //Join face + case 3: + if(out_degree(source(halfedge(ed,*polyhedron()),*polyhedron()),*polyhedron())<3 || + out_degree(target(halfedge(ed,*polyhedron()),*polyhedron()),*polyhedron())<3) + tempInstructions("Faces not joined : the two ends of the edge must have a degree of at least 3.", + "Select the edge separating the faces you want to join."); + else + { + polyhedron()->join_facet(halfedge(ed, *polyhedron())); + poly_item->invalidateOpenGLBuffers(); + } + break; + //Collapse edge + case 5: + if(!is_triangle_mesh(*polyhedron())) + { + tempInstructions("Edge not collapsed : the graph must be triangulated.", + "Select the edge you want to collapse."); + } + else if(!CGAL::Euler::does_satisfy_link_condition(ed, *polyhedron())) + { + tempInstructions("Edge not collapsed : link condition not satidfied.", + "Select the edge you want to collapse."); + } + else + { + CGAL::Euler::collapse_edge(ed, *polyhedron()); + polyhedron_item()->invalidateOpenGLBuffers(); + tempInstructions("Edge collapsed.", + "Select the edge you want to collapse."); + } + break; + //Flip edge + case 6: + + //check preconditions + if(facet_degree(halfedge(ed, *polyhedron())) == 3 && facet_degree(halfedge(ed, *polyhedron())->opposite()) == 3) + { + CGAL::Euler::flip_edge(halfedge(ed, *polyhedron()), *polyhedron()); + polyhedron_item()->invalidateOpenGLBuffers(); + } + else + { + tempInstructions("Edge not selected : incident facets must be triangles.", + "Select the edge you want to flip."); + } + + break; + //Add vertex and face to border + case 9: + { + static Halfedge_handle t; + if(!first_selected) + { + bool found = false; + Halfedge_handle hc = halfedge(ed, *polyhedron()); + if(hc->is_border()) + { + t = hc; + found = true; + } + else if(hc->opposite()->is_border()) + { + t = hc->opposite(); + found = true; + } + if(found) + { + first_selected = true; + temp_selected_edges.insert(edge(t, *polyhedron())); + temp_selected_vertices.insert(t->vertex()); + invalidateOpenGLBuffers(); + Q_EMIT updateInstructions("Select second edge. (2/2)"); + } + else + { + tempInstructions("Edge not selected : no border found.", + "Select a border edge. (1/2)"); + } + } + else + { + bool found(false), is_equal(true), is_border(false); + Halfedge_handle hc = halfedge(ed, *polyhedron()); + //seems strange but allows to use break efficiently + for(int i=0; i< 2; i++) + { + //if the selected halfedge is not a border, stop and signal it. + if(hc->is_border()) + is_border = true; + else if(hc->opposite()->is_border()) + { + hc = halfedge(ed, *polyhedron())->opposite(); + is_border = true; + } + if(!is_border) + break; + //if the halfedges are the same, stop and signal it. + if(hc == t) + { + is_equal = true; + break; + } + is_equal = false; + //if the halfedges are not on the same border, stop and signal it. + boost::graph_traits::halfedge_descriptor iterator = next(t, *polyhedron()); + while(iterator != t) + { + if(iterator == hc) + { + found = true; + Halfedge_handle res = CGAL::Euler::add_vertex_and_face_to_border(t,hc, *polyhedron()); + //res seems to be the opposite of what it is said to be in the doc. + if(res->vertex() == hc->vertex()) + res = res->opposite(); + //create and add a point point + + Polyhedron::Point_3 a = t->vertex()->point(); + Polyhedron::Point_3 b = t->opposite()->vertex()->point(); + Polyhedron::Point_3 c = t->opposite()->next()->vertex()->point(); + double x = b.x()+a.x()-c.x() ; + double y = b.y()+a.y()-c.y() ; + double z = b.z()+a.z()-c.z() ; + res->vertex()->point() = Polyhedron::Point_3(x,y,z); + break; + } + iterator = next(iterator, *polyhedron()); + } + } + if(is_equal) + { + tempInstructions("Edge not selected : halfedges must be different.", + "Select the second edge."); + } + else if(!is_border || !found) + { + tempInstructions("Edge not selected : no shared border found.", + "Select the second edge."); + } + else + { + first_selected = false; + + + temp_selected_edges.clear(); + temp_selected_vertices.clear(); + invalidateOpenGLBuffers(); + polyhedron_item()->invalidateOpenGLBuffers(); + tempInstructions("Face and vertex added.", + "Select a border edge. (1/2)"); + } + } + break; + } + //Add face to border + case 10: + { + static Halfedge_handle t; + if(!first_selected) + { + bool found = false; + Halfedge_handle hc = halfedge(ed, *polyhedron()); + if(hc->is_border()) + { + t = hc; + found = true; + } + else if(hc->opposite()->is_border()) + { + t = hc->opposite(); + found = true; + } + if(found) + { + first_selected = true; + temp_selected_edges.insert(edge(t, *polyhedron())); + temp_selected_vertices.insert(t->vertex()); + invalidateOpenGLBuffers(); + Q_EMIT updateInstructions("Select second edge. (2/2)"); + set_active_handle_type(static_cast(2)); + } + else + { + tempInstructions("Edge not selected : no border found.", + "Select a border edge. (1/2)"); + } + } + else + { + bool found(false), is_equal(true), is_next(true), is_border(false); + Halfedge_handle hc = halfedge(ed, *polyhedron()); + //seems strange but allows to use break efficiently + for(int i= 0; i<1; i++) + { + //if the selected halfedge is not a border, stop and signal it. + if(hc->is_border()) + is_border = true; + else if(hc->opposite()->is_border()) + { + hc = hc->opposite(); + is_border = true; + } + if(!is_border) + break; + //if the halfedges are the same, stop and signal it. + if(hc == t) + { + is_equal = true; + break; + } + is_equal = false; + //if the halfedges are adjacent, stop and signal it. + if(next(t, *polyhedron()) == hc || next(hc, *polyhedron()) == t) + { + is_next = true; + break; + } + is_next = false; + //if the halfedges are not on the same border, stop and signal it. + boost::graph_traits::halfedge_descriptor iterator = next(t, *polyhedron()); + while(iterator != t) + { + if(iterator == hc) + { + found = true; + CGAL::Euler::add_face_to_border(t,hc, *polyhedron()); + break; + } + iterator = next(iterator, *polyhedron()); + } + } + if(is_equal) + { + tempInstructions("Edge not selected : halfedges must be different.", + "Select the second edge. (2/2)"); + } + + else if(is_next) + { + tempInstructions("Edge not selected : halfedges must not be adjacent.", + "Select the second edge. (2/2)"); + } + else if(!is_border || !found) + { + tempInstructions("Edge not selected : no shared border found.", + "Select the second edge. (2/2)"); + } + else + { + first_selected = false; + temp_selected_vertices.clear(); + temp_selected_edges.clear(); + invalidateOpenGLBuffers(); + polyhedron_item()->invalidateOpenGLBuffers(); + tempInstructions("Face added.", + "Select a border edge. (1/2)"); + } + } + break; + } + } + } + is_treated = true; + return false; +} + +bool Scene_polyhedron_selection_item::treat_selection(const std::vector& selection) +{ + return treat_classic_selection(selection); +} + +bool Scene_polyhedron_selection_item::treat_selection(const std::set& selection) +{ + if(!is_treated) + { + Facet_handle fh = *selection.begin(); + Selection_traits tr(this); + switch(operation_mode) + { + //classic selection + case -1: + { + return treat_classic_selection(selection); + break; + } + //Split vertex + case 1: + { + static Polyhedron::Halfedge_handle h1; + //stores first fh and emit change label + if(!first_selected) + { + bool found = false; + //test preco + Polyhedron::Halfedge_around_facet_circulator hafc = fh->facet_begin(); + Polyhedron::Halfedge_around_facet_circulator end = hafc; + CGAL_For_all(hafc, end) + { + if(hafc->vertex()==to_split_vh) + { + h1 = hafc; + found = true; + break; + } + } + if(found) + { + first_selected = true; + temp_selected_facets.insert(fh); + invalidateOpenGLBuffers(); + Q_EMIT updateInstructions("Select the second facet. (3/3)"); + } + else + tempInstructions("Facet not selected : no valid halfedge", + "Select first facet. (2/3)"); + } + //call the function with point and facets. + else + { + //get the right halfedges + Polyhedron::Halfedge_handle h2; + bool found = false; + Polyhedron::Halfedge_around_facet_circulator hafc = fh->facet_begin(); + Polyhedron::Halfedge_around_facet_circulator end = hafc; + CGAL_For_all(hafc, end) + { + if(hafc->vertex()==to_split_vh) + { + h2 = hafc; + found = true; + break; + } + } + + if(found &&(h1 != h2)) + { + Polyhedron::Halfedge_handle hhandle = CGAL::Euler::split_vertex(h1,h2,*polyhedron()); + + temp_selected_facets.clear(); + Polyhedron::Point_3 p1t = h1->vertex()->point(); + Polyhedron::Point_3 p1s = h1->opposite()->vertex()->point(); + double x = p1t.x() + 0.01 * (p1s.x() - p1t.x()); + double y = p1t.y() + 0.01 * (p1s.y() - p1t.y()); + double z = p1t.z() + 0.01 * (p1s.z() - p1t.z()); + hhandle->opposite()->vertex()->point() = Polyhedron::Point_3(x,y,z);; + first_selected = false; + temp_selected_vertices.clear(); + invalidateOpenGLBuffers(); + //reset selection mode + set_active_handle_type(static_cast(0)); + poly_item->invalidateOpenGLBuffers(); + tempInstructions("Vertex splitted.", "Select the vertex you want splitted. (1/3)"); + } + else if(h1 == h2) + { + tempInstructions("Facet not selected : same as the first.", "Select the second facet. (3/3)"); + } + else + { + tempInstructions("Facet not selected : no valid halfedge.", "Select the second facet. (3/3)"); + } + } + break; + } + //Split face + case 4: + if(is_triangle(fh->halfedge(), *poly)) + { + tempInstructions("Facet not selected : Facet must not be a triangle.", + "Select the facet you want to split (degree >= 4). (1/3)"); + } + else + { + to_split_fh = fh; + temp_selected_facets.insert(to_split_fh); + invalidateOpenGLBuffers(); + //set to select vertex + set_active_handle_type(static_cast(0)); + Q_EMIT updateInstructions("Select first vertex. (2/3)"); + } + break; + //Add center vertex + case 7: + if(fh->halfedge()->is_border()) + { + tempInstructions("Facet not selected : Facet must not be null.", + "Select a Facet. (1/3)"); + } + else + { + Polyhedron::Halfedge_around_facet_circulator hafc = fh->facet_begin(); + Polyhedron::Halfedge_around_facet_circulator end = hafc; + + double x(0), y(0), z(0); + int total(0); + CGAL_For_all(hafc, end) + { + x+=hafc->vertex()->point().x(); y+=hafc->vertex()->point().y(); z+=hafc->vertex()->point().z(); + total++; + } + Polyhedron::Halfedge_handle hhandle = CGAL::Euler::add_center_vertex(fh->facet_begin(), *polyhedron()); + if(total !=0) + hhandle->vertex()->point() = Polyhedron::Point_3(x/(double)total, y/(double)total, z/(double)total); + poly_item->invalidateOpenGLBuffers(); + + } + break; + } + } + is_treated = true; + return false; +} + +void Scene_polyhedron_selection_item::tempInstructions(QString s1, QString s2) +{ + m_temp_instructs = s2; + Q_EMIT updateInstructions(QString("%1").arg(s1)); + QTimer timer; + timer.singleShot(5500, this, SLOT(emitTempInstruct())); +} +void Scene_polyhedron_selection_item::emitTempInstruct() +{ + Q_EMIT updateInstructions(QString("%1").arg(m_temp_instructs)); +} + +void Scene_polyhedron_selection_item::on_Ctrlz_pressed() +{ + first_selected = false; + temp_selected_vertices.clear(); + temp_selected_edges.clear(); + temp_selected_facets.clear(); + are_temp_buffers_filled = false; + set_operation_mode(operation_mode); + Q_EMIT itemChanged(); +} diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 2c09d6b6beb..ce3135e48f8 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -26,6 +26,7 @@ #include #include +#include namespace PMP = CGAL::Polygon_mesh_processing; @@ -184,13 +185,15 @@ public: Scene_polyhedron_selection_item() : Scene_polyhedron_item_decorator(NULL, false) { - for(int i=0; i<3; i++) + original_sel_mode = static_cast(0); + this ->operation_mode = -1; + for(int i=0; i<6; i++) { addVaos(i); vaos[i]->create(); } - for(int i=0; i<7; i++) + for(int i=0; i<10; i++) { buffers[i].create(); } @@ -198,28 +201,36 @@ public: nb_points = 0; nb_lines = 0; this->setColor(facet_color); + first_selected = false; + is_treated = false; + poly_need_update = false; } Scene_polyhedron_selection_item(Scene_polyhedron_item* poly_item, QMainWindow* mw) : Scene_polyhedron_item_decorator(NULL, false) { + original_sel_mode = static_cast(0); + this ->operation_mode = -1; nb_facets = 0; nb_points = 0; nb_lines = 0; - for(int i=0; i<3; i++) + for(int i=0; i<6; i++) { addVaos(i); vaos[i]->create(); } - for(int i=0; i<7; i++) + for(int i=0; i<8; i++) { buffers[i].create(); } init(poly_item, mw); this->setColor(facet_color); invalidateOpenGLBuffers(); + first_selected = false; + is_treated = false; + poly_need_update = false; } ~Scene_polyhedron_selection_item() @@ -237,9 +248,12 @@ protected: SLOT(selected(const std::set&))); connect(&k_ring_selector, SIGNAL(selected(const std::set&)), this, SLOT(selected(const std::set&))); + connect(poly_item, SIGNAL(selection_done()), this, SLOT(update_poly())); + connect(&k_ring_selector, SIGNAL(endSelection()), this,SLOT(endSelection())); connect(&k_ring_selector, SIGNAL(toogle_insert(bool)), this,SLOT(toggle_insert(bool))); k_ring_selector.init(poly_item, mw, Active_handle::VERTEX, -1); + connect(&k_ring_selector, SIGNAL(resetIsTreated()), this, SLOT(resetIsTreated())); QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); viewer->installEventFilter(this); @@ -787,14 +801,32 @@ public: } Q_SIGNALS: + void updateInstructions(QString); void simplicesSelected(CGAL::Three::Scene_item*); public Q_SLOTS: + void update_poly() + { + if(poly_need_update) + poly_item->invalidateOpenGLBuffers(); + } + void on_Ctrlz_pressed(); + void emitTempInstruct(); + void resetIsTreated() { is_treated = false;} + void save_handleType() + { + original_sel_mode = get_active_handle_type(); + } + + void set_operation_mode(int mode); + void invalidateOpenGLBuffers() { // do not use decorator function, which calls changed on poly_item which cause deletion of AABB // poly_item->invalidateOpenGLBuffers(); are_buffers_filled = false; + are_temp_buffers_filled = false; + poly = polyhedron(); compute_bbox(); } // slots are called by signals of polyhedron_k_ring_selector @@ -820,6 +852,14 @@ public Q_SLOTS: protected: bool eventFilter(QObject* /*target*/, QEvent * gen_event) { + if(gen_event->type() == QEvent::KeyPress + && static_cast(gen_event)->key()==Qt::Key_Z) + { + QKeyEvent *keyEvent = static_cast(gen_event); + if(keyEvent->modifiers().testFlag(Qt::ControlModifier)) + on_Ctrlz_pressed(); + } + if(!visible() || !k_ring_selector.state.shift_pressing) { return false; } if(gen_event->type() == QEvent::Wheel) { @@ -849,24 +889,23 @@ protected: } } - template - bool treat_selection(const HandleRange& selection) - { - typedef typename HandleRange::value_type HandleType; - Selection_traits tr(this); - bool any_change = false; - if(is_insert) { - BOOST_FOREACH(HandleType h, selection) - any_change |= tr.container().insert(h).second; - } - else{ - BOOST_FOREACH(HandleType h, selection) - any_change |= (tr.container().erase(h)!=0); - } - if(any_change) { invalidateOpenGLBuffers(); Q_EMIT itemChanged(); } - return any_change; - } +//Generic class + template + bool treat_selection(const HandleRange&) + { + qDebug()<<"ERROR : unknown HandleRange"; +return false; +} +template + bool treat_classic_selection(const HandleRange& selection); + +//Specialization for set + bool treat_selection(const std::set& selection); + bool treat_selection(const std::set& selection); + bool treat_selection(const std::set& selection); + bool treat_selection(const std::vector& selection); + Facet_handle face(Facet_handle fh) { return fh; } @@ -904,6 +943,7 @@ protected: } } + public: Is_selected_property_map selected_edges_pmap(std::vector& mark) @@ -943,11 +983,27 @@ public: Selection_set_vertex selected_vertices; Selection_set_facet selected_facets; Selection_set_edge selected_edges; // stores one halfedge for each pair (halfedge with minimum address) + + Selection_set_vertex temp_selected_vertices; + Selection_set_facet temp_selected_facets; + Selection_set_edge temp_selected_edges; // stores one halfedge for each pair (halfedge with minimum address) // QColor vertex_color, facet_color, edge_color; private: - + bool poly_need_update; + mutable bool are_temp_buffers_filled; + //Specifies Selection/edition mode + bool first_selected; + int operation_mode; + QString m_temp_instructs; + bool is_treated; + Vertex_handle to_split_vh; + Facet_handle to_split_fh; + edge_descriptor to_join_ed; + Active_handle::Type original_sel_mode; + //Only needed for the triangulation + Polyhedron* poly; mutable std::vector positions_facets; mutable std::vector normals; mutable std::vector positions_lines; @@ -955,11 +1011,29 @@ private: mutable std::size_t nb_facets; mutable std::size_t nb_points; mutable std::size_t nb_lines; + + mutable std::vector positions_temp_facets; + mutable std::vector temp_normals; + mutable std::vector positions_temp_lines; + mutable std::vector positions_temp_points; + mutable std::size_t nb_temp_facets; + mutable std::size_t nb_temp_points; + mutable std::size_t nb_temp_lines; + mutable QOpenGLShaderProgram *program; + using CGAL::Three::Scene_item::initializeBuffers; void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const; + void initialize_temp_buffers(CGAL::Three::Viewer_interface *viewer) const; void computeElements() const; + void compute_any_elements(std::vector &p_facets, std::vector &p_lines, std::vector &p_points, std::vector &p_normals, + const Selection_set_vertex& p_sel_vertex, const Selection_set_facet &p_sel_facet, const Selection_set_edge &p_sel_edges) const; + void compute_temp_elements() const; + template + void triangulate_facet(Facet_handle, const FaceNormalPmap&, + std::vector &p_facets,std::vector &p_normals) const; + void tempInstructions(QString s1, QString s2); }; -#endif +#endif