Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ namespace CGAL {

namespace Polygon_mesh_processing {

/*!
* \ingroup PMP_combinatorial_repair_grp
*
* \brief Policies controlling how duplicate polygons are handled.
*/
enum Erase_policy {
ERASE_ALL, KEEP_ONE, KEEP_ONE_IF_ODD
};

namespace internal {

template <typename Stream, typename Polygon>
Expand Down Expand Up @@ -900,12 +909,13 @@ DuplicateOutputIterator collect_duplicate_polygons(const PointRange& points,
/// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{erase_all_duplicates}
/// \cgalParamDescription{Parameter to indicate, when multiple polygons are duplicates,
/// whether all the duplicate polygons should be removed
/// or if one (arbitrarily chosen) face should be kept.}
/// \cgalParamType{Boolean}
/// \cgalParamDefault{`false`}
/// \cgalParamNBegin{erase_policy}
/// \cgalParamDescription{specifies the policy applied when multiple polygons are duplicates.
/// `CGAL::Polygon_mesh_processing::ERASE_ALL` remove all duplicates.
/// `CGAL::Polygon_mesh_processing::KEEP_ONE` keep one arbitrarily chosen polygon.
/// `CGAL::Polygon_mesh_processing::KEEP_ONE_IF_ODD` keep one polygon if their number is odd, and remove all of them otherwise.}
/// \cgalParamType{`CGAL::Polygon_mesh_processing::Erase_policy`}
/// \cgalParamDefault{`CGAL::Polygon_mesh_processing::KEEP_ONE`}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{require_same_orientation}
Expand All @@ -927,15 +937,29 @@ std::size_t merge_duplicate_polygons_in_polygon_soup(const PointRange& points,
{
using parameters::get_parameter;
using parameters::choose_parameter;
using parameters::is_default_parameter;

typedef typename CGAL::internal::Polygon_types<PointRange, PolygonRange>::P_ID P_ID;

const bool erase_all_duplicates = choose_parameter(get_parameter(np, internal_np::erase_all_duplicates), false);
Erase_policy erase_policy = choose_parameter(get_parameter(np, internal_np::erase_policy), KEEP_ONE);
#ifndef CGAL_NO_DEPRECATED_CODE
if constexpr(parameters::is_default_parameter<NamedParameters, internal_np::erase_policy_t>::value)
if(choose_parameter(get_parameter(np, internal_np::erase_all_duplicates), false)){
// CGAL_warning_msg(false, "The named parameter 'erase_all_duplicates' is deprecated. Use 'erase_policy' instead.");
erase_policy = ERASE_ALL;
}
#endif // CGAL_NO_DEPRECATED_CODE

const bool same_orientation = choose_parameter(get_parameter(np, internal_np::require_same_orientation), false);

#ifdef CGAL_PMP_REPAIR_POLYGON_SOUP_VERBOSE_PP
std::cout << "Only polygons with the same orientation are duplicates: " << std::boolalpha << same_orientation << std::endl;
std::cout << "Erase all duplicate polygons: " << std::boolalpha << erase_all_duplicates << std::endl;
if(erase_policy == ERASE_ALL)
std::cout << "Erase policy: ERASE_ALL" << std::endl;
else if(erase_policy == KEEP_ONE)
std::cout << "Erase policy: KEEP_ONE" << std::endl;
else if(erase_policy == KEEP_ONE_IF_ODD)
std::cout << "Erase policy: KEEP_ONE_IF_ODD" << std::endl;
#endif

typedef typename GetPolygonGeomTraits<PointRange, PolygonRange, NamedParameters>::type Traits;
Expand Down Expand Up @@ -972,7 +996,9 @@ std::size_t merge_duplicate_polygons_in_polygon_soup(const PointRange& points,
const std::vector<P_ID>& duplicate_polygons = all_duplicate_polygons.back();
CGAL_assertion(duplicate_polygons.size() >= 2);

std::size_t i = erase_all_duplicates ? 0 : 1;
std::size_t i = (erase_policy==ERASE_ALL) ? 0 :
(erase_policy==KEEP_ONE) ? 1 :
/* (erase_policy==KEEP_ONE_IF_ODD) ?*/ duplicate_polygons.size() % 2;
for(; i<duplicate_polygons.size(); ++i)
{
const P_ID polygon_to_remove_id = duplicate_polygons[i];
Expand Down Expand Up @@ -1122,12 +1148,13 @@ struct Polygon_soup_fixer<PointRange, PolygonRange, std::array<PID, N> >
/// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{erase_all_duplicates}
/// \cgalParamDescription{Parameter to indicate, when multiple polygons are duplicates,
/// whether all the duplicate polygons should be removed
/// or if one (arbitrarily chosen) face should be kept.}
/// \cgalParamType{Boolean}
/// \cgalParamDefault{`false`}
/// \cgalParamNBegin{erase_policy}
/// \cgalParamDescription{specifies the policy applied when multiple polygons are duplicates. <BR>
/// `CGAL::Polygon_mesh_processing::ERASE_ALL` remove all duplicates. <BR>
/// `CGAL::Polygon_mesh_processing::KEEP_ONE` keep one arbitrarily chosen polygon. <BR>
/// `CGAL::Polygon_mesh_processing::KEEP_ONE_IF_ODD` keep one polygon if their number is odd, and remove all of them otherwise.}
/// \cgalParamType{`CGAL::Polygon_mesh_processing::Erase_policy`}
/// \cgalParamDefault{`CGAL::Polygon_mesh_processing::KEEP_ONE`}
/// \cgalParamNEnd
///
/// \cgalParamNBegin{require_same_orientation}
Expand Down
39 changes: 35 additions & 4 deletions PMP_Mesh_repair/test/PMP_Mesh_repair/test_repair_polygon_soup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,46 @@ void test_merge_duplicate_polygons(const bool /*verbose*/ = false)
// Remove all duplicates
polygons_copy = polygons;
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons_copy,
params::erase_all_duplicates(true)
params::erase_policy(PMP::ERASE_ALL)
.require_same_orientation(false));
assert(res == 5 && polygons_copy.size() == 1);

// Remove all duplicates but different orientations are different polygons
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons,
params::erase_all_duplicates(true)
polygons_copy = polygons;
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons_copy,
params::erase_policy(PMP::ERASE_ALL)
.require_same_orientation(true));
assert(res == 2 && polygons.size() == 4);
assert(res == 2 && polygons_copy.size() == 4);

// Remove even duplicates
polygons_copy = polygons;
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons_copy,
params::erase_policy(PMP::KEEP_ONE_IF_ODD)
.require_same_orientation(false));
assert(res == 4 && polygons_copy.size() == 2);

// Remove all duplicates (Deprecated parameter)
polygons_copy = polygons;
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons_copy,
params::erase_all_duplicates(true)
.require_same_orientation(false));
assert(res == 5 && polygons_copy.size() == 1);

// Contradiction between erase_policy KEEP_ONE and the deprecated parameter
polygons_copy = polygons;
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons_copy,
params::erase_all_duplicates(true)
.erase_policy(PMP::KEEP_ONE)
.require_same_orientation(false));
assert(res == 3 && polygons_copy.size() == 3);

// Contradiction between erase_policy KEEP_ONE_IF_ODD and the deprecated parameter
polygons_copy = polygons;
res = PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons_copy,
params::erase_all_duplicates(true)
.erase_policy(PMP::KEEP_ONE_IF_ODD)
.require_same_orientation(false));
assert(res == 4 && polygons_copy.size() == 2);
}

void test_simplify_polygons(const bool /*verbose*/ = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ CGAL_add_named_parameter(clip_volume_t, clip_volume, clip_volume)
CGAL_add_named_parameter(use_compact_clipper_t, use_compact_clipper, use_compact_clipper)
CGAL_add_named_parameter(output_iterator_t, output_iterator, output_iterator)
CGAL_add_named_parameter(erase_all_duplicates_t, erase_all_duplicates, erase_all_duplicates)
CGAL_add_named_parameter(erase_policy_t, erase_policy, erase_policy)
CGAL_add_named_parameter(require_same_orientation_t, require_same_orientation, require_same_orientation)
CGAL_add_named_parameter(face_size_map_t, face_size_map, face_size_map)
CGAL_add_named_parameter(snapping_tolerance_t, snapping_tolerance, snapping_tolerance)
Expand Down
Loading