diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h
index 805bd77fac9..ca508c31526 100644
--- a/BGL/include/CGAL/boost/graph/parameters_interface.h
+++ b/BGL/include/CGAL/boost/graph/parameters_interface.h
@@ -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)
diff --git a/Installation/changes.md b/Installation/changes.md
index 79a4a66ba6a..0449302d811 100644
--- a/Installation/changes.md
+++ b/Installation/changes.md
@@ -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()`
diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt
index 6de00b16019..b7eb0e9775c 100644
--- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt
+++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt
@@ -295,6 +295,14 @@ If this parameter is not provided, the perturbation is not deterministic
Type: `unsigned int` \n
Default: 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
*/
diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt
index 2b3f0a0682e..b9cc6903fd2 100644
--- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt
+++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt
@@ -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
diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt
index 14ad740fd37..a95b6552992 100644
--- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt
+++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt
@@ -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
diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h
index 2dcd314b767..da869cd192c 100644
--- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h
+++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h
@@ -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
bool does_bound_a_volume(const TriangleMesh& tm, const NamedParameters& np)
diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h
index 7839b1adb36..14b4f39a615 100644
--- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h
+++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h
@@ -27,16 +27,18 @@
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
-
+#include
namespace CGAL {
namespace Polygon_mesh_processing {
@@ -253,7 +255,7 @@ void reverse_face_orientations(PolygonMesh& pmesh)
typedef typename boost::graph_traits::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
+void recursive_orient_volume_ccs( TriangleMesh& tm,
+ Vpm& vpm,
+ Fid_map& fid_map,
+ const std::vector& xtrm_vertices,
+ boost::dynamic_bitset<>& cc_handled,
+ const std::vector& face_cc,
+ std::size_t xtrm_cc_id,
+ bool is_parent_outward_oriented)
+{
+ typedef boost::graph_traits Graph_traits;
+ typedef typename Graph_traits::face_descriptor face_descriptor;
+ typedef Side_of_triangle_mesh Side_of_tm;
+ std::vector 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 cc_inside;
+ for(std::size_t id=0; id 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
+ 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(
+ 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(
+ 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
+void orient(TriangleMesh& tm, const NamedParameters& np)
+{
+ typedef boost::graph_traits 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::const_type Vpm;
+ typedef typename GetFaceIndexMap::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 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 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 > 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
+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
+void orient_to_bound_a_volume(TriangleMesh& tm,
+ const NamedParameters& np)
+{
+ typedef boost::graph_traits Graph_traits;
+ typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
+ typedef typename GetVertexPointMap::const_type Vpm;
+ typedef typename GetFaceIndexMap::const_type Fid_map;
+ typedef typename Kernel_traits<
+ typename boost::property_traits::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 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 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; idget(vpm,xtrm_vertices[xtrm_cc_id]).z())
+ xtrm_cc_id=id;
+
+ bool is_parent_outward_oriented =
+ ! orient_outward;
+
+ internal::recursive_orient_volume_ccs(tm, vpm, fid_map,
+ xtrm_vertices,
+ cc_handled,
+ face_cc,
+ xtrm_cc_id,
+ is_parent_outward_oriented);
+}
+
+template
+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
diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt
index 280e4696db4..69da1b5132f 100644
--- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt
+++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt
@@ -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)
diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp
new file mode 100644
index 00000000000..bc52731eeb6
--- /dev/null
+++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_orient_cc.cpp
@@ -0,0 +1,130 @@
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace PMP = CGAL::Polygon_mesh_processing;
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef CGAL::Surface_mesh SMesh;
+
+template
+bool test_orientation(TriangleMesh& tm, bool is_positive, const NamedParameters& np)
+{
+ typedef boost::graph_traits Graph_traits;
+ typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
+ typedef typename Graph_traits::face_descriptor face_descriptor;
+ typedef typename CGAL::GetVertexPointMap::const_type Vpm;
+ typedef typename CGAL::GetFaceIndexMap::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 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 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 > 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> 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::type Ppmap;
+ typedef boost::property_map::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;
+}
diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Inside_out_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Inside_out_plugin.cpp
index bc4353a7a95..aac56db2864 100644
--- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Inside_out_plugin.cpp
+++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Inside_out_plugin.cpp
@@ -2,6 +2,7 @@
#include
#include
#include
+#include
#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->item(index))
- || qobject_cast(scene->item(index))
- || qobject_cast(scene->item(index));
+ if(action == actionInsideOut)
+ return qobject_cast(scene->item(index))
+ || qobject_cast(scene->item(index))
+ || qobject_cast(scene->item(index));
+ else if(action == actionOrientCC)
+ return qobject_cast(scene->item(index))
+ || qobject_cast(scene->item(index));
+ return false;
}
public Q_SLOTS:
void on_actionInsideOut_triggered();
+ void on_actionOrientCC_triggered();
private:
+ QAction* actionInsideOut;
+ QAction* actionOrientCC;
QList _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->item(index));
+
+ Scene_surface_mesh_item* sm_item =
+ qobject_cast(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"