Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an Euler operation to remove degree 2 vertices #8234

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
72 changes: 67 additions & 5 deletions BGL/include/CGAL/boost/graph/Euler_operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
#ifndef CGAL_EULER_OPERATIONS_H
#define CGAL_EULER_OPERATIONS_H

#include <stdexcept>
#include <algorithm>
#include <vector>

#include <boost/graph/graph_traits.hpp>
#include <CGAL/boost/graph/properties.h>

Expand All @@ -27,6 +23,10 @@

#include <boost/container/small_vector.hpp>

#include <algorithm>
#include <stdexcept>
#include <vector>

namespace CGAL {

/// \cond SKIP_IN_MANUAL
Expand Down Expand Up @@ -1866,10 +1866,72 @@ bool satisfies_link_condition(typename boost::graph_traits<Graph>::edge_descript
}
/// \endcond
#endif

/// removes the target vertex of `h`, merging its incident edges into a single edge.
/// \pre `degree(target(h, g), g) == 2`.
/// \pre there is no pre-existing edge between source(h, g) and target(next(h, g), g)
template <typename Graph>
typename boost::graph_traits<Graph>::halfedge_descriptor
remove_degree_2_vertex(const typename boost::graph_traits<Graph>::halfedge_descriptor h,
Graph& g)
{
typedef boost::graph_traits<Graph> Traits;
typedef typename Traits::vertex_descriptor vertex_descriptor;
typedef typename Traits::halfedge_descriptor halfedge_descriptor;
typedef typename Traits::face_descriptor face_descriptor;

CGAL_precondition(degree(target(h, g), g) == 2);

vertex_descriptor v = target(h, g);
halfedge_descriptor h1 = h;
halfedge_descriptor h2 = opposite(next(h1, g), g);

if(is_border(h1, g))
std::swap(h1, h2);

vertex_descriptor v1 = source(h1, g);
vertex_descriptor v2 = source(h2, g);

bool exists;
halfedge_descriptor huv;
std::tie(huv, exists) = halfedge(v1, v2, g);
if(exists)
return boost::graph_traits<Graph>::null_halfedge();

if(is_border(h2, g))
{
CGAL_assertion(!is_border(h1, g));

halfedge_descriptor oh1 = opposite(h1, g);
halfedge_descriptor nnh1 = next(next(h1, g), g);
halfedge_descriptor ph2 = prev(h2, g);
face_descriptor f1 = face(h1, g);

set_target(h1, v2, g);
set_halfedge(v2, ph2, g);
set_next(h1, nnh1, g);
set_next(ph2, oh1, g);
set_halfedge(f1, h1, g); // in case it was nh1

remove_edge(edge(h2, g), g);
remove_vertex(v, g);

return h1;
}
else
{
CGAL_assertion(!is_border(h1, g) && !is_border(h2, g));

halfedge_descriptor ph1 = prev(h1, g);
halfedge_descriptor ph2 = prev(h2, g);
Euler::remove_center_vertex(h, g);
return Euler::split_face(ph1, ph2, g);
}
}

/// @}

} // namespace Euler

} // namespace CGAL

#endif /* CGAL_EULER_OPERATIONS_H */
16 changes: 8 additions & 8 deletions Lab/demo/Lab/Plugins/PMP/Orient_soup_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,28 +109,28 @@ QList<QAction*> CGAL_Lab_orient_soup_plugin::actions() const {
<< actionClean;
}

void set_vcolors(SMesh* smesh, std::vector<CGAL::IO::Color> colors)
void set_vcolors(SMesh* smesh, const std::vector<CGAL::IO::Color>& colors)
{
typedef SMesh SMesh;
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
SMesh::Property_map<vertex_descriptor, CGAL::IO::Color> vcolors =
smesh->property_map<vertex_descriptor, CGAL::IO::Color >("v:color").value();

SMesh::Property_map<vertex_descriptor, CGAL::IO::Color> vcolors;
bool created;
boost::tie(vcolors, created) = smesh->add_property_map<SMesh::Vertex_index,CGAL::IO::Color>("v:color",CGAL::IO::Color(0,0,0));
std::tie(vcolors, created) = smesh->add_property_map<vertex_descriptor,CGAL::IO::Color>("v:color",CGAL::IO::Color(0,0,0));
assert(colors.size()==smesh->number_of_vertices());
int color_id = 0;
for(vertex_descriptor vd : vertices(*smesh))
vcolors[vd] = colors[color_id++];
}

void set_fcolors(SMesh* smesh, std::vector<CGAL::IO::Color> colors)
void set_fcolors(SMesh* smesh, const std::vector<CGAL::IO::Color>& colors)
{
typedef SMesh SMesh;
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
SMesh::Property_map<face_descriptor, CGAL::IO::Color> fcolors =
smesh->property_map<face_descriptor, CGAL::IO::Color >("f:color").value();

SMesh::Property_map<face_descriptor, CGAL::IO::Color> fcolors;
bool created;
boost::tie(fcolors, created) = smesh->add_property_map<SMesh::Face_index,CGAL::IO::Color>("f:color",CGAL::IO::Color(0,0,0));
std::tie(fcolors, created) = smesh->add_property_map<face_descriptor,CGAL::IO::Color>("f:color",CGAL::IO::Color(0,0,0));
assert(colors.size()==smesh->number_of_faces());
int color_id = 0;
for(face_descriptor fd : faces(*smesh))
Expand Down
8 changes: 7 additions & 1 deletion Lab/demo/Lab/Plugins/PMP/Selection_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,13 +977,19 @@ public Q_SLOTS:
}
//Add vertex and face to border
case 9:
{
QPixmap pm(":/cgal/Lab/resources/euler_deg2.png");
ui_widget.docImage_Label->setPixmap(pm);
break;
}
case 10:
{
QPixmap pm(":/cgal/Lab/resources/add_facet1.png");
lrineau marked this conversation as resolved.
Show resolved Hide resolved
ui_widget.docImage_Label->setPixmap(pm);
break;
}
//add facet to border
case 10:
case 11:
{
QPixmap pm(":/cgal/Lab/resources/add_facet2.png");
ui_widget.docImage_Label->setPixmap(pm);
Expand Down
12 changes: 8 additions & 4 deletions Lab/demo/Lab/Plugins/PMP/Selection_widget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>613</width>
<width>630</width>
<height>409</height>
</rect>
</property>
Expand All @@ -21,7 +21,6 @@
<widget class="QPushButton" name="Create_selection_item_button">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
Expand Down Expand Up @@ -72,7 +71,7 @@
<item>
<widget class="QTabWidget" name="selectionOrEuler">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab_3">
<attribute name="title">
Expand Down Expand Up @@ -618,6 +617,11 @@
<string>Remove center vertex</string>
</property>
</item>
<item>
<property name="text">
<string>Remove degree 2 vertex</string>
</property>
</item>
<item>
<property name="text">
<string>Add vertex and face to border (Advanced)</string>
Expand All @@ -638,7 +642,7 @@
<item>
<widget class="QLabel" name="instructionsLabel">
<property name="text">
<string>Instructions
<string>Instructions

</string>
</property>
Expand Down
43 changes: 30 additions & 13 deletions Lab/demo/Lab/Scene_polyhedron_selection_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -779,19 +779,26 @@ void Scene_polyhedron_selection_item::set_operation_mode(int mode)
//set the selection type to vertex
set_active_handle_type(static_cast<Active_handle::Type>(0));
break;
//Add vertex and face to border
//Remove degree 2 vertex
case 9:
Q_EMIT updateInstructions("Select the vertex you want to remove."
"Warning: This will clear the undo stack.");
//set the selection type to vertex
set_active_handle_type(static_cast<Active_handle::Type>(0));
break;
//Add vertex and 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<Active_handle::Type>(2));
break;
//Add face to border
case 10:
case 11:
Q_EMIT updateInstructions("Select a border edge. (1/2)");
//set the selection type to Edge
set_active_handle_type(static_cast<Active_handle::Type>(2));
break;
case 11:
case 12:
Q_EMIT updateInstructions("Select a vertex. (1/2)");
//set the selection type to Edge
set_active_handle_type(static_cast<Active_handle::Type>(0));
Expand Down Expand Up @@ -1011,7 +1018,24 @@ bool Scene_polyhedron_selection_item::treat_selection(const std::set<fg_vertex_d
}
break;
}
case 11:
//Remove degree 2 vertex
case 9:
{
if(degree(vh,*polyhedron()) == 2)
{
CGAL::Euler::remove_degree_2_vertex(halfedge(vh,*polyhedron()), *polyhedron());
polyhedron_item()->invalidateOpenGLBuffers();
}
else
{
d->tempInstructions("Vertex not selected: The vertex must have degree 2 (and not be incident to a triangle)",
"Select the vertex you want to remove."
"Warning: This will clear the undo stack.");
}
break;
}
//Move point
case 12:
CGAL::QGLViewer* viewer = Three::mainViewer();
const CGAL::qglviewer::Vec offset = viewer->offset();
if(viewer->manipulatedFrame() != d->manipulated_frame)
Expand Down Expand Up @@ -1056,13 +1080,6 @@ bool Scene_polyhedron_selection_item::treat_selection(const std::set<fg_vertex_d
return false;
}

//returns true if halfedge's facet's degree >= degree
/*
std::size_t facet_degree(fg_halfedge_descriptor h, const Face_graph& polyhedron)
{
return degree(h,polyhedron);
}
*/
bool Scene_polyhedron_selection_item:: treat_selection(const std::set<fg_edge_descriptor>& selection)
{
VPmap vpm = get(CGAL::vertex_point, *polyhedron());
Expand Down Expand Up @@ -1203,7 +1220,7 @@ bool Scene_polyhedron_selection_item:: treat_selection(const std::set<fg_edge_de

break;
//Add vertex and face to border
case 9:
case 10:
{
static fg_halfedge_descriptor t;
if(!d->first_selected)
Expand Down Expand Up @@ -1255,7 +1272,7 @@ bool Scene_polyhedron_selection_item:: treat_selection(const std::set<fg_edge_de
break;
}
//Add face to border
case 10:
case 11:
{
static fg_halfedge_descriptor t;
if(!d->first_selected)
Expand Down
4 changes: 2 additions & 2 deletions Lab/demo/Lab/Scene_surface_mesh_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,15 +545,15 @@ void Scene_surface_mesh_item_priv::compute_elements(Scene_item_rendering_helper:
}
if(name.testFlag(Scene_item_rendering_helper::NORMALS))
{
EPICK::Vector_3 n = fnormals[fd];
const EPICK::Vector_3& n = fnormals[fd];
CPF::add_normal_in_buffer(n, flat_normals);
}
if(name.testFlag(Scene_item_rendering_helper::COLORS))
{
if(has_fpatch_id)
{
//The sharp features detection produces patch ids >=1, this
//is meant to insure the wanted id is in the range [min,max]
//is meant to ensure the wanted id is in the range [min,max]
QColor c = item->color_vector()[fpatch_id_map[fd] - min_patch_id];
CGAL::IO::Color color(c.red(),c.green(),c.blue());
CPF::add_color_in_buffer(color, f_colors);
Expand Down