diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index b3d44074380..ca7a1feed3e 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -65,6 +65,7 @@ CGAL_add_named_parameter(outward_orientation_t, outward_orientation, outward_ori CGAL_add_named_parameter(overlap_test_t, overlap_test, do_overlap_test_of_bounded_sides) CGAL_add_named_parameter(preserve_genus_t, preserve_genus, preserve_genus) CGAL_add_named_parameter(new_face_visitor_t, new_face_visitor, new_face_visitor) +CGAL_add_named_parameter(throw_on_self_intersection_t, throw_on_self_intersection, throw_on_self_intersection) // 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/BGL/test/BGL/test_cgal_bgl_named_params.cpp b/BGL/test/BGL/test_cgal_bgl_named_params.cpp index 013931e028e..1efa27797da 100644 --- a/BGL/test/BGL/test_cgal_bgl_named_params.cpp +++ b/BGL/test/BGL/test_cgal_bgl_named_params.cpp @@ -73,6 +73,7 @@ void test(const NamedParameters& np) assert(get_param(np, CGAL::internal_np::nb_points_per_area_unit).v == 32); assert(get_param(np, CGAL::internal_np::nb_points_per_distance_unit).v == 33); assert(get_param(np, CGAL::internal_np::new_face_visitor).v == 42); + assert(get_param(np, CGAL::internal_np::throw_on_self_intersection).v == 43); // Named parameters that we use in the package 'Surface Mesh Simplification' assert(get_param(np, CGAL::internal_np::get_cost_policy).v == 34); @@ -138,6 +139,7 @@ void test(const NamedParameters& np) check_same_type<32>(get_param(np, CGAL::internal_np::nb_points_per_area_unit)); check_same_type<33>(get_param(np, CGAL::internal_np::nb_points_per_distance_unit)); check_same_type<42>(get_param(np, CGAL::internal_np::new_face_visitor)); + check_same_type<43>(get_param(np, CGAL::internal_np::throw_on_self_intersection)); // Named parameters that we use in the package 'Surface Mesh Simplification' check_same_type<34>(get_param(np, CGAL::internal_np::get_cost_policy)); @@ -202,6 +204,7 @@ int main() .preserve_genus(A<40>(40)) .verbosity_level(A<41>(41)) .new_face_visitor(A<42>(42)) + .throw_on_self_intersection(A<43>(43)) ); return EXIT_SUCCESS; diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index f6608194fe1..6840262b9d8 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -38,6 +38,10 @@ Release date: September 2018 - Add in corefinement-related functions a new named parameter `new_face_visitor` that make it possible to pass a visitor to the function in order to track the creation of new faces. +- Add in all corefinement-related functions a named parameter `throw_on_self_intersection` + (that replace the `bool` parameter in `corefine()`) that enables to check for + self-intersections faces involved in the intersection before trying to corefine the + input meshes. Release 4.12 ------------ diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index 16eecfbadd8..41be61c81be 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -318,6 +318,15 @@ to track the creation of new faces. \b Default `CGAL::Polygon_mesh_processing::Corefinement::Default_new_face_visitor` \cgalNPEnd +\cgalNPBegin{throw_on_self_intersection} \anchor PMP_throw_on_self_intersection +Parameter used in corefinement-related functions to make the functions throw an exception in +case some faces involved in the intersection of the input are self-intersecting +and make the operation impossible with the current version of the code. +\n +\b Type : `bool` \n +\b Default value is `false` +\cgalNPEnd + \cgalNPTableEnd 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 baacb794d71..e029ba98837 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/corefinement.h @@ -284,9 +284,11 @@ corefine_and_compute_boolean_operations( const cpp11::tuple& nps_out, - const bool throw_on_self_intersection = false ) + NamedParametersOut3>& nps_out) { + const bool throw_on_self_intersection = + boost::choose_param(get_param(np1, internal_np::throw_on_self_intersection), false); + // Vertex point maps //for input meshes typedef typename GetVertexPointMap corefine_and_compute_boolean_operations( TriangleMesh& tm1, TriangleMesh& tm2, - const cpp11::array< boost::optional,4>& output, - const bool throw_on_self_intersection = false ) + const cpp11::array< boost::optional,4>& output) { using namespace CGAL::Polygon_mesh_processing::parameters; return corefine_and_compute_boolean_operations(tm1, tm2, output, all_default(), all_default(), cpp11::make_tuple(all_default(), all_default(), - all_default(), all_default()), - throw_on_self_intersection); + all_default(), all_default())); } #undef CGAL_COREF_SET_OUTPUT_VERTEX_POINT_MAP @@ -495,6 +495,11 @@ corefine_and_compute_boolean_operations( * \cgalParamBegin{new_face_visitor} a class model of `PMPCorefinementNewFaceVisitor` * that is used to track the creation of new faces (`np1` only) * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh, + * the set of triangles closed to the intersection of `tm1` and `tm2` will be + * checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found (`np1` only). + * \cgalParamEnd * \cgalNamedParamsEnd * * @param np_out optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below @@ -623,10 +628,6 @@ corefine_and_compute_difference( TriangleMesh& tm1, * @param tm2 second input triangulated surface mesh * @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below - * @param throw_on_self_intersection if `true`, for each input triangle mesh, - * the set of triangles closed to the intersection of `tm1` and `tm2` will be - * checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` - * will be thrown if at least one is found. * * \cgalNamedParamsBegin * \cgalParamBegin{vertex_point_map} @@ -640,6 +641,11 @@ corefine_and_compute_difference( TriangleMesh& tm1, * \cgalParamBegin{new_face_visitor} a class model of `PMPCorefinementNewFaceVisitor` * that is used to track the creation of new faces (`np1` only) * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh, + * the set of triangles closed to the intersection of `tm1` and `tm2` will be + * checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found (`np1` only). + * \cgalParamEnd * \cgalNamedParamsEnd * */ @@ -650,9 +656,11 @@ corefine_and_compute_difference( TriangleMesh& tm1, corefine( TriangleMesh& tm1, TriangleMesh& tm2, const NamedParameters1& np1, - const NamedParameters2& np2, - const bool throw_on_self_intersection = false) + const NamedParameters2& np2) { + const bool throw_on_self_intersection = + boost::choose_param(get_param(np1, internal_np::throw_on_self_intersection), false); + // Vertex point maps typedef typename GetVertexPointMap::type Vpm; @@ -1006,22 +1014,60 @@ template void corefine( TriangleMesh& tm1, TriangleMesh& tm2, - const NamedParameters1& np1, - const bool throw_on_self_intersection = false) + const NamedParameters1& np1) { using namespace CGAL::Polygon_mesh_processing::parameters; - corefine(tm1, tm2, np1, all_default(), throw_on_self_intersection); + corefine(tm1, tm2, np1, all_default()); +} + +template +void +corefine( TriangleMesh& tm1, + TriangleMesh& tm2) +{ + using namespace CGAL::Polygon_mesh_processing::parameters; + corefine(tm1, tm2, all_default(), all_default()); +} + +#ifndef CGAL_NO_DEPRECATED_CODE + template + void + corefine( TriangleMesh& tm1, + TriangleMesh& tm2, + const NamedParameters1& np1, + const NamedParameters2& np2, + const bool throw_on_self_intersection) +{ + corefine(tm1, tm2, np1.throw_on_self_intersection(throw_on_self_intersection), np2); +} + +template +void +corefine( TriangleMesh& tm1, + TriangleMesh& tm2, + const NamedParameters1& np1, + const bool throw_on_self_intersection) +{ + namespace params = CGAL::Polygon_mesh_processing::parameters; + corefine(tm1, tm2, + np1.throw_on_self_intersection(throw_on_self_intersection), + params::all_default()); } template void corefine( TriangleMesh& tm1, TriangleMesh& tm2, - const bool throw_on_self_intersection = false) + const bool throw_on_self_intersection) { - using namespace CGAL::Polygon_mesh_processing::parameters; - corefine(tm1, tm2, all_default(), all_default(), throw_on_self_intersection); + namespace params = CGAL::Polygon_mesh_processing::parameters; + corefine(tm1, tm2, + params::throw_on_self_intersection(throw_on_self_intersection), + params::all_default()); } +#endif ///// autorefine ///// namespace experimental { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h index b2c380e23d0..0d866d51544 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h @@ -1640,10 +1640,6 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range, * @param tm2 second input triangulated surface mesh * @param polyline_output output iterator of polylines. Each polyline will be * given as a vector of points - * @param throw_on_self_intersection if `true`, for each input triangle mesh, - * the set of triangles closed to the intersection of `tm1` and `tm2` will be - * checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` - * will be thrown if at least one is found. * @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below * @@ -1652,6 +1648,11 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range, * a property map with the points associated to the vertices of `tm1` * (`tm2`). The two property map types must be the same. * \cgalParamEnd + * \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh, + * the set of triangles closed to the intersection of `tm1` and `tm2` will be + * checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception` + * will be thrown if at least one is found (`np1` only). + * \cgalParamEnd * \cgalNamedParamsEnd * */ @@ -1664,9 +1665,11 @@ surface_intersection(const TriangleMesh& tm1, const TriangleMesh& tm2, OutputIterator polyline_output, const NamedParameters1& np1, - const NamedParameters2& np2, - const bool throw_on_self_intersection=false) + const NamedParameters2& np2) { + const bool throw_on_self_intersection = + boost::choose_param(get_param(np1, internal_np::throw_on_self_intersection), false); + typedef typename GetVertexPointMap::const_type Vpm; typedef typename GetVertexPointMap +OutputIterator +surface_intersection(const TriangleMesh& tm1, + const TriangleMesh& tm2, + OutputIterator polyline_output, + const NamedParameters1& np1, + const NamedParameters2& np2, + const bool throw_on_self_intersection) +{ + return surface_intersection(tm1, tm2, polyline_output, + np1.throw_on_self_intersection(throw_on_self_intersection), np2); +} + +template +OutputIterator +surface_intersection(const TriangleMesh& tm1, + const TriangleMesh& tm2, + OutputIterator polyline_output, + const bool throw_on_self_intersection) +{ + return surface_intersection(tm1, tm2, polyline_output, + CGAL::Polygon_mesh_processing::parameters::throw_on_self_intersection(throw_on_self_intersection), + CGAL::Polygon_mesh_processing::parameters::all_default()); +} +#endif + namespace experimental { template diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Corefinement_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Corefinement_plugin.cpp index 68c90b62a24..b4f592f8681 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Corefinement_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Corefinement_plugin.cpp @@ -12,6 +12,8 @@ using namespace CGAL::Three; namespace PMP = CGAL::Polygon_mesh_processing; +namespace params = PMP::parameters; + class Polyhedron_demo_corefinement_sm_plugin : public QObject, public Polyhedron_demo_plugin_helper @@ -165,7 +167,7 @@ private: } QApplication::setOverrideCursor(Qt::WaitCursor); - PMP::corefine(*item1->face_graph(), *item2->face_graph()); + PMP::corefine(*item1->face_graph(), *item2->face_graph(), params::throw_on_self_intersection(true)); item1->invalidateOpenGLBuffers(); item2->invalidateOpenGLBuffers(); scene->itemChanged(item2); @@ -197,7 +199,7 @@ private: { case CRF_UNION: P = *first_item->face_graph(), Q = *item->face_graph(); - if (! PMP::corefine_and_compute_union(P, Q, *new_poly) ) + if (! PMP::corefine_and_compute_union(P, Q, *new_poly, params::throw_on_self_intersection(true)) ) { delete new_poly; messages->warning(tr("The result of the requested operation is not manifold and has not been computed.")); @@ -209,7 +211,7 @@ private: break; case CRF_INTER: P = *first_item->polyhedron(), Q = *item->polyhedron(); - if (! PMP::corefine_and_compute_intersection(P, Q, *new_poly) ) + if (! PMP::corefine_and_compute_intersection(P, Q, *new_poly, params::throw_on_self_intersection(true)) ) { delete new_poly; messages->warning(tr("The result of the requested operation is not manifold and has not been computed.")); @@ -224,7 +226,7 @@ private: CGAL_FALLTHROUGH; case CRF_MINUS: P = *first_item->polyhedron(), Q = *item->polyhedron(); - if (! PMP::corefine_and_compute_difference(P, Q, *new_poly) ) + if (! PMP::corefine_and_compute_difference(P, Q, *new_poly, params::throw_on_self_intersection(true)) ) { delete new_poly; messages->warning(tr("The result of the requested operation is not manifold and has not been computed."));