Merge branch 'maxGimeno/PMP_orient_connected_components-GF' into cgal/master

This commit is contained in:
Sébastien Loriot 2017-12-19 17:34:51 +01:00
commit d1597f2fb5
10 changed files with 537 additions and 7 deletions

View File

@ -56,6 +56,7 @@ CGAL_add_named_parameter(number_of_points_per_edge_t, number_of_points_per_edge,
CGAL_add_named_parameter(number_of_points_on_edges_t, number_of_points_on_edges, number_of_points_on_edges)
CGAL_add_named_parameter(nb_points_per_area_unit_t, nb_points_per_area_unit, number_of_points_per_area_unit)
CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_unit, number_of_points_per_distance_unit)
CGAL_add_named_parameter(outward_orientation_t, outward_orientation, outward_orientation)
// List of named parameters that we use in the package 'Surface Mesh Simplification'
CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost)

View File

@ -69,6 +69,10 @@ Release date: April 2018
### Polygon Mesh Processing
- Added two functions for orienting connected components :
- `CGAL::Polygon_mesh_processing::orient()`
- `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()`
- Added new functions for feature detection and feature-guided
segmentation:
- `CGAL::Polygon_mesh_processing::detect_sharp_edges()`

View File

@ -295,6 +295,14 @@ If this parameter is not provided, the perturbation is not deterministic
<b>Type:</b> `unsigned int` \n
<b>Default:</b> the random number generator is initialized with `CGAL::Random()`
\cgalNPEnd
\cgalNPBegin{outward_orientation} \anchor PMP_outward_orientation
Parameter used in orientation functions to choose between an outward or inward orientation.
\n
\b Type : `bool` \n
\b Default value is `true`
\cgalNPEnd
\cgalNPTableEnd
*/

View File

@ -109,6 +109,8 @@ and provides a list of the parameters that are used in this package.
- `CGAL::Polygon_mesh_processing::is_outward_oriented()`
- `CGAL::Polygon_mesh_processing::reverse_face_orientations()`
- `CGAL::Polygon_mesh_processing::orient_polygon_soup()`
- `CGAL::Polygon_mesh_processing::orient()`
- `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()`
## Combinatorial Repairing Functions ##
- \link PMP_repairing_grp `CGAL::Polygon_mesh_processing::stitch_borders()` \endlink

View File

@ -430,6 +430,13 @@ As a consequence, the normal computed for each face (see Section
The \ref PolygonSoupExample puts these functions at work on a polygon soup.
The function `CGAL::Polygon_mesh_processing::orient()` makes each connected component
of a closed polygon mesh outward or inward oriented.
The function `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()` orients
the connected components of a closed polygon mesh so that it bounds a volume
(see \ref coref_def_subsec for the precise definition).
****************************************
\section PMPRepairing Combinatorial Repairing

View File

@ -150,6 +150,7 @@ bool recursive_does_bound_a_volume(const TriangleMesh& tm,
* \cgalParamEnd
* \cgalNamedParamsEnd
*
* \see `CGAL::Polygon_mesh_processing::orient_to_bound_a_volume()`
*/
template <class TriangleMesh, class NamedParameters>
bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np)

View File

@ -27,16 +27,18 @@
#include <algorithm>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/Projection_traits_xy_3.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/iterator.h>
#include <boost/foreach.hpp>
#include <boost/unordered_set.hpp>
#include <boost/dynamic_bitset.hpp>
namespace CGAL {
namespace Polygon_mesh_processing {
@ -253,7 +255,7 @@ void reverse_face_orientations(PolygonMesh& pmesh)
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
BOOST_FOREACH(face_descriptor fd, faces(pmesh)){
reverse_orientation(halfedge(fd,pmesh),pmesh);
}
}
// Note: A border edge is now parallel to its opposite edge.
// We scan all border edges for this property. If it holds, we
// reorient the associated hole and search again until no border
@ -334,7 +336,313 @@ void reverse_face_orientations(const FaceRange& face_range, PolygonMesh& pmesh)
}
}
}
namespace internal {
template <class Kernel, class TriangleMesh, class VD, class Fid_map, class Vpm>
void recursive_orient_volume_ccs( TriangleMesh& tm,
Vpm& vpm,
Fid_map& fid_map,
const std::vector<VD>& xtrm_vertices,
boost::dynamic_bitset<>& cc_handled,
const std::vector<std::size_t>& face_cc,
std::size_t xtrm_cc_id,
bool is_parent_outward_oriented)
{
typedef boost::graph_traits<TriangleMesh> Graph_traits;
typedef typename Graph_traits::face_descriptor face_descriptor;
typedef Side_of_triangle_mesh<TriangleMesh, Kernel, Vpm> Side_of_tm;
std::vector<face_descriptor> cc_faces;
BOOST_FOREACH(face_descriptor fd, faces(tm))
{
if(face_cc[get(fid_map, fd)]==xtrm_cc_id)
cc_faces.push_back(fd);
}
// first check that the orientation of the current cc is consistant with its
// parent cc containing it
bool new_is_parent_outward_oriented = internal::is_outward_oriented(
xtrm_vertices[xtrm_cc_id], tm, parameters::vertex_point_map(vpm));
if (new_is_parent_outward_oriented==is_parent_outward_oriented)
{
Polygon_mesh_processing::reverse_face_orientations(cc_faces, tm);
new_is_parent_outward_oriented = !new_is_parent_outward_oriented;
}
cc_handled.set(xtrm_cc_id);
std::size_t nb_cc = cc_handled.size();
// get all cc that are inside xtrm_cc_id
typename Side_of_tm::AABB_tree aabb_tree(cc_faces.begin(), cc_faces.end(),
tm, vpm);
Side_of_tm side_of_cc(aabb_tree);
std::vector<std::size_t> cc_inside;
for(std::size_t id=0; id<nb_cc; ++id)
{
if (cc_handled.test(id)) continue;
if (side_of_cc(get(vpm,xtrm_vertices[id]))==ON_BOUNDED_SIDE)
cc_inside.push_back(id);
}
// check whether we need another recursion for cc inside xtrm_cc_id
if (!cc_inside.empty())
{
std::size_t new_xtrm_cc_id = cc_inside.front();
boost::dynamic_bitset<> new_cc_handled(nb_cc,0);
new_cc_handled.set();
new_cc_handled.reset(new_xtrm_cc_id);
cc_handled.set(new_xtrm_cc_id);
std::size_t nb_candidates = cc_inside.size();
for (std::size_t i=1;i<nb_candidates;++i)
{
std::size_t candidate = cc_inside[i];
if(get(vpm,xtrm_vertices[candidate]).z() >
get(vpm,xtrm_vertices[new_xtrm_cc_id]).z()) new_xtrm_cc_id=candidate;
new_cc_handled.reset(candidate);
cc_handled.set(candidate);
}
internal::recursive_orient_volume_ccs<Kernel>(
tm, vpm, fid_map, xtrm_vertices, new_cc_handled, face_cc,
new_xtrm_cc_id, new_is_parent_outward_oriented);
}
// now explore remaining cc included in the same cc as xtrm_cc_id
boost::dynamic_bitset<> cc_not_handled = ~cc_handled;
std::size_t new_xtrm_cc_id = cc_not_handled.find_first();
if (new_xtrm_cc_id == cc_not_handled.npos) return ;
for (std::size_t candidate = cc_not_handled.find_next(new_xtrm_cc_id);
candidate < cc_not_handled.npos;
candidate = cc_not_handled.find_next(candidate))
{
if(get(vpm,xtrm_vertices[candidate]).z() > get(vpm,xtrm_vertices[new_xtrm_cc_id]).z())
new_xtrm_cc_id = candidate;
}
internal::recursive_orient_volume_ccs<Kernel>(
tm, vpm, fid_map, xtrm_vertices, cc_handled, face_cc,
new_xtrm_cc_id, is_parent_outward_oriented);
}
}//end internal
/**
* \ingroup PMP_orientation_grp
* makes each connected component of a closed triangulated surface mesh
* inward or outward oriented.
*
* @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` .
* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`,
* as a named parameter, then it must be initialized.
* @tparam NamedParameters a sequence of \ref namedparameters
*
* @param tm a closed triangulated surface mesh
* @param np optional sequence of \ref namedparameters among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map}
* the property map with the points associated to the vertices of `tm`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `TriangleMesh`
* \cgalParamEnd
* \cgalParamBegin{face_index_map}
* a property map containing the index of each face of `tm`.
* \cgalParamEnd
* \cgalParamBegin{outward_orientation}
* if set to `true` (default) indicates that each connected component will be outward oriented,
* (inward oriented if `false`).
* \cgalParamEnd
* \cgalNamedParamsEnd
*/
template<class TriangleMesh, class NamedParameters>
void orient(TriangleMesh& tm, const NamedParameters& np)
{
typedef boost::graph_traits<TriangleMesh> Graph_traits;
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
typedef typename Graph_traits::face_descriptor face_descriptor;
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters>::const_type Vpm;
typedef typename GetFaceIndexMap<TriangleMesh,
NamedParameters>::const_type Fid_map;
CGAL_assertion(is_triangle_mesh(tm));
CGAL_assertion(is_valid(tm));
CGAL_assertion(is_closed(tm));
using boost::choose_param;
using boost::get_param;
bool orient_outward = choose_param(
get_param(np, internal_np::outward_orientation),true);
Vpm vpm = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm));
Fid_map fid_map = choose_param(get_param(np, internal_np::face_index),
get_const_property_map(boost::face_index, tm));
std::vector<std::size_t> face_cc(num_faces(tm), std::size_t(-1));
// set the connected component id of each face
std::size_t nb_cc = connected_components(tm,
bind_property_maps(fid_map,make_property_map(face_cc)),
parameters::face_index_map(fid_map));
// extract a vertex with max z coordinate for each connected component
std::vector<vertex_descriptor> xtrm_vertices(nb_cc, Graph_traits::null_vertex());
BOOST_FOREACH(vertex_descriptor vd, vertices(tm))
{
halfedge_descriptor test_hd = halfedge(vd, tm);
if(test_hd == Graph_traits::null_halfedge())
continue;
face_descriptor test_face = face(halfedge(vd, tm), tm);
if(test_face == Graph_traits::null_face())
test_face = face(opposite(halfedge(vd, tm), tm), tm);
CGAL_assertion(test_face != Graph_traits::null_face());
std::size_t cc_id = face_cc[get(fid_map,test_face )];
if (xtrm_vertices[cc_id]==Graph_traits::null_vertex())
xtrm_vertices[cc_id]=vd;
else
if (get(vpm, vd).z()>get(vpm,xtrm_vertices[cc_id]).z())
xtrm_vertices[cc_id]=vd;
}
std::vector<std::vector<face_descriptor> > ccs(nb_cc);
BOOST_FOREACH(face_descriptor fd, faces(tm))
{
ccs[face_cc[get(fid_map,fd)]].push_back(fd);
}
//orient ccs outward
for(std::size_t id=0; id<nb_cc; ++id)
{
if(internal::is_outward_oriented(xtrm_vertices[id], tm, np)
!= orient_outward)
{
reverse_face_orientations(ccs[id], tm);
}
}
}
template<class TriangleMesh>
void orient(TriangleMesh& tm)
{
orient(tm, parameters::all_default());
}
/** \ingroup PMP_orientation_grp
*
* orients the connected components of `tm` to make it bound a volume.
* See \ref coref_def_subsec for a precise definition.
*
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`.
* If `TriangleMesh` has an internal property map for `CGAL::face_index_t`,
* as a named parameter, then it must be initialized.
* @tparam NamedParameters a sequence of \ref namedparameters
*
* @param tm a closed triangulated surface mesh
* @param np optional sequence of \ref namedparameters among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map}
* the property map with the points associated to the vertices of `tm`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `TriangleMesh`
* \cgalParamEnd
* \cgalParamBegin{face_index_map}
* a property map containing the index of each face of `tm`.
* \cgalParamEnd
* \cgalParamBegin{outward_orientation}
* if set to `true` (default) the outer connected components will be outward oriented (inward oriented if set to `false`).
* If the outer connected components are inward oriented, it means that the infinity will be considered
* as part of the volume bounded by `tm`.
* \cgalParamEnd
* \cgalNamedParamsEnd
*
* \see `CGAL::Polygon_mesh_processing::does_bound_a_volume()`
*/
template <class TriangleMesh, class NamedParameters>
void orient_to_bound_a_volume(TriangleMesh& tm,
const NamedParameters& np)
{
typedef boost::graph_traits<TriangleMesh> Graph_traits;
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters>::const_type Vpm;
typedef typename GetFaceIndexMap<TriangleMesh,
NamedParameters>::const_type Fid_map;
typedef typename Kernel_traits<
typename boost::property_traits<Vpm>::value_type >::Kernel Kernel;
if (!is_closed(tm)) return;
if (!is_triangle_mesh(tm)) return;
using boost::choose_param;
using boost::get_param;
bool orient_outward = choose_param(
get_param(np, internal_np::outward_orientation),true);
Vpm vpm = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm));
Fid_map fid_map = choose_param(get_param(np, internal_np::face_index),
get_const_property_map(boost::face_index, tm));
std::vector<std::size_t> face_cc(num_faces(tm), std::size_t(-1));
// set the connected component id of each face
std::size_t nb_cc = connected_components(tm,
bind_property_maps(fid_map,make_property_map(face_cc)),
parameters::face_index_map(fid_map));
if (nb_cc == 1)
{
if( orient_outward != is_outward_oriented(tm))
reverse_face_orientations(faces(tm), tm);
return ;
}
boost::dynamic_bitset<> cc_handled(nb_cc, 0);
// extract a vertex with max z coordinate for each connected component
std::vector<vertex_descriptor> xtrm_vertices(nb_cc, Graph_traits::null_vertex());
BOOST_FOREACH(vertex_descriptor vd, vertices(tm))
{
std::size_t cc_id = face_cc[get(fid_map, face(halfedge(vd, tm), tm))];
if (xtrm_vertices[cc_id]==Graph_traits::null_vertex())
xtrm_vertices[cc_id]=vd;
else
if (get(vpm, vd).z()>get(vpm,xtrm_vertices[cc_id]).z())
xtrm_vertices[cc_id]=vd;
}
//extract a vertex with max z amongst all components
std::size_t xtrm_cc_id=0;
for(std::size_t id=1; id<nb_cc; ++id)
if (get(vpm, xtrm_vertices[id]).z()>get(vpm,xtrm_vertices[xtrm_cc_id]).z())
xtrm_cc_id=id;
bool is_parent_outward_oriented =
! orient_outward;
internal::recursive_orient_volume_ccs<Kernel>(tm, vpm, fid_map,
xtrm_vertices,
cc_handled,
face_cc,
xtrm_cc_id,
is_parent_outward_oriented);
}
template <class TriangleMesh>
void orient_to_bound_a_volume(TriangleMesh& tm)
{
orient_to_bound_a_volume(tm, parameters::all_default());
}
} // namespace Polygon_mesh_processing
} // namespace CGAL
#endif // CGAL_ORIENT_POLYGON_MESH_H

View File

@ -95,6 +95,7 @@ endif()
create_single_source_cgal_program("autorefinement_sm.cpp")
create_single_source_cgal_program("triangulate_hole_polyline_test.cpp")
create_single_source_cgal_program("surface_intersection_sm_poly.cpp" )
create_single_source_cgal_program("test_orient_cc.cpp")
if( TBB_FOUND )
CGAL_target_use_TBB(test_pmp_distance)

View File

@ -0,0 +1,130 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/orientation.h>
#include <CGAL/Polygon_mesh_processing/corefinement.h>
#include <iostream>
#include <fstream>
namespace PMP = CGAL::Polygon_mesh_processing;
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Surface_mesh<Kernel::Point_3> SMesh;
template<class TriangleMesh, class NamedParameters>
bool test_orientation(TriangleMesh& tm, bool is_positive, const NamedParameters& np)
{
typedef boost::graph_traits<TriangleMesh> Graph_traits;
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
typedef typename Graph_traits::face_descriptor face_descriptor;
typedef typename CGAL::GetVertexPointMap<TriangleMesh,
NamedParameters>::const_type Vpm;
typedef typename CGAL::GetFaceIndexMap<TriangleMesh,
NamedParameters>::const_type Fid_map;
Vpm vpm = boost::choose_param(get_param(np, CGAL::internal_np::vertex_point),
CGAL::get_const_property_map(boost::vertex_point, tm));
Fid_map fid_map = boost::choose_param(get_param(np, CGAL::internal_np::face_index),
CGAL::get_const_property_map(boost::face_index, tm));
std::vector<std::size_t> face_cc(num_faces(tm), std::size_t(-1));
// set the connected component id of each face
std::size_t nb_cc = PMP::connected_components(tm,
CGAL::bind_property_maps(fid_map,CGAL::make_property_map(face_cc)),
PMP::parameters::face_index_map(fid_map));
// extract a vertex with max z coordinate for each connected component
std::vector<vertex_descriptor> xtrm_vertices(nb_cc, Graph_traits::null_vertex());
BOOST_FOREACH(vertex_descriptor vd, vertices(tm))
{
face_descriptor test_face = face(halfedge(vd, tm), tm);
if(test_face == Graph_traits::null_face())
test_face = face(opposite(halfedge(vd, tm), tm), tm);
std::size_t cc_id = face_cc[get(fid_map,test_face )];
if (xtrm_vertices[cc_id]==Graph_traits::null_vertex())
xtrm_vertices[cc_id]=vd;
else
if (get(vpm, vd).z()>get(vpm,xtrm_vertices[cc_id]).z())
xtrm_vertices[cc_id]=vd;
}
std::vector<std::vector<face_descriptor> > ccs(nb_cc);
BOOST_FOREACH(face_descriptor fd, faces(tm))
{
ccs[face_cc[get(fid_map,fd)]].push_back(fd);
}
//test ccs orientation
for(std::size_t id=0; id<nb_cc; ++id)
{
if((!PMP::internal::is_outward_oriented(xtrm_vertices[id], tm, np)
&& is_positive)
|| (PMP::internal::is_outward_oriented(xtrm_vertices[id], tm, np)
&& !is_positive))
{
std::cerr<<" the orientation failed"<<std::endl;
return false;
}
}
return true;
}
int main()
{
std::ifstream input("data-coref/nested_cubes_invalid_volume.off");
assert(input);
SMesh sm1, sm2, sm3, sm4, volume;
input >> sm1;
sm2 = sm1;
sm3 = sm1;
sm4 = sm1;
volume = sm1;
PMP::orient(sm1);
if(!test_orientation(sm1, true, PMP::parameters::all_default()))
return 1;
typedef boost::property_map<SMesh, CGAL::vertex_point_t>::type Ppmap;
typedef boost::property_map<SMesh, CGAL::face_index_t>::type Fidmap;
Ppmap vpmap2 = get(CGAL::vertex_point, sm2);
Fidmap fidmap2 = get(CGAL::face_index, sm2);
PMP::orient(sm2, PMP::parameters::vertex_point_map(vpmap2)
.face_index_map(fidmap2));
if(!test_orientation(sm2, true, PMP::parameters::vertex_point_map(vpmap2)
.face_index_map(fidmap2)))
{
std::cerr << "ERROR for test1\n";
return 1;
}
PMP::orient(sm3, PMP::parameters::outward_orientation(false));
if(!test_orientation(sm3, false, PMP::parameters::all_default()))
{
std::cerr << "ERROR for test2\n";
return 1;
}
Ppmap vpmap4 = get(CGAL::vertex_point, sm4);
Fidmap fidmap4 = get(CGAL::face_index, sm4);
PMP::orient(sm4, PMP::parameters::vertex_point_map(vpmap4)
.face_index_map(fidmap4)
.outward_orientation(false));
if(!test_orientation(sm4, false, PMP::parameters::vertex_point_map(vpmap4)
.face_index_map(fidmap4)))
{
std::cerr << "ERROR for test3\n";
return 1;
}
PMP::orient_to_bound_a_volume(volume);
if( !PMP::does_bound_a_volume(volume))
{
std::cerr << "ERROR for test4\n";
return 1;
}
return 0;
}

View File

@ -2,6 +2,7 @@
#include <QAction>
#include <QStringList>
#include <QMainWindow>
#include <QInputDialog>
#include "Scene_polyhedron_item.h"
#include "Scene_polygon_soup_item.h"
#include "Scene_surface_mesh_item.h"
@ -29,26 +30,43 @@ public:
Messages_interface*)
{
scene = scene_interface;
QAction* actionInsideOut = new QAction(tr("Inside Out"), mw);
this->mw = mw;
actionInsideOut = new QAction(tr("Inside Out"), mw);
actionInsideOut->setProperty("subMenuName", "Polygon Mesh Processing");
connect(actionInsideOut, SIGNAL(triggered()), this, SLOT(on_actionInsideOut_triggered()));
_actions << actionInsideOut;
actionOrientCC = new QAction(tr("Orient Connected Components"), mw);
actionOrientCC->setProperty("subMenuName", "Polygon Mesh Processing");
connect(actionOrientCC, SIGNAL(triggered()), this, SLOT(on_actionOrientCC_triggered()));
_actions << actionOrientCC;
}
bool applicable(QAction*) const {
bool applicable(QAction* action) const {
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
return qobject_cast<Scene_polyhedron_item*>(scene->item(index))
|| qobject_cast<Scene_polygon_soup_item*>(scene->item(index))
|| qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
if(action == actionInsideOut)
return qobject_cast<Scene_polyhedron_item*>(scene->item(index))
|| qobject_cast<Scene_polygon_soup_item*>(scene->item(index))
|| qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
else if(action == actionOrientCC)
return qobject_cast<Scene_polyhedron_item*>(scene->item(index))
|| qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
return false;
}
public Q_SLOTS:
void on_actionInsideOut_triggered();
void on_actionOrientCC_triggered();
private:
QAction* actionInsideOut;
QAction* actionOrientCC;
QList<QAction*> _actions;
Scene_interface *scene;
QMainWindow* mw;
}; // end Polyhedron_demo_inside_out_plugin
void Polyhedron_demo_inside_out_plugin::on_actionInsideOut_triggered()
@ -94,4 +112,54 @@ void Polyhedron_demo_inside_out_plugin::on_actionInsideOut_triggered()
}
}
void Polyhedron_demo_inside_out_plugin::on_actionOrientCC_triggered()
{
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_polyhedron_item* poly_item =
qobject_cast<Scene_polyhedron_item*>(scene->item(index));
Scene_surface_mesh_item* sm_item =
qobject_cast<Scene_surface_mesh_item*>(scene->item(index));
if(poly_item || sm_item)
{
QStringList items;
items << tr("Outward") << tr("Inward");
bool ok;
QString item = QInputDialog::getItem(mw, tr("QInputDialog::getItem()"),
tr("The connected components should be oriented:"), items, 0, false, &ok);
if (!ok )
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
if(poly_item) {
Polyhedron* pMesh = poly_item->polyhedron();
if(pMesh){
if(is_closed(*pMesh))
CGAL::Polygon_mesh_processing::orient_to_bound_a_volume(*pMesh, item==items.first());
else
CGAL::Polygon_mesh_processing::orient(*pMesh, item==items.first());
poly_item->invalidateOpenGLBuffers();
}
}
else if(sm_item) {
SMesh* pMesh = sm_item->polyhedron();
if(pMesh){
if(is_closed(*pMesh))
CGAL::Polygon_mesh_processing::orient_to_bound_a_volume(*pMesh, item==items.first());
else
CGAL::Polygon_mesh_processing::orient(*pMesh, item==items.first());
sm_item->invalidateOpenGLBuffers();
}
}
// update scene
scene->itemChanged(index);
// default cursor
QApplication::restoreOverrideCursor();
}
}
#include "Inside_out_plugin.moc"