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"