Skip to content

Commit 75fd9c6

Browse files
authored
Merge pull request #6740 from MaelRL/PMP-Fix_stitch_NP
Add proper traits usage to PMP::stitch_borders
2 parents e4d1600 + 70143a6 commit 75fd9c6

File tree

2 files changed

+102
-36
lines changed

2 files changed

+102
-36
lines changed

Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1804,7 +1804,7 @@ bool remove_degenerate_edges(TriangleMesh& tmesh)
18041804
// - `Collinear_3` to check whether 3 points are collinear
18051805
// - `Less_xyz_3` to compare lexicographically two points
18061806
// - `Equal_3` to check whether 2 points are identical.
1807-
// For each functor Foo, a function `Foo foo_object()` must be provided.}
1807+
// For each functor `Foo`, a function `Foo foo_object()` must be provided.}
18081808
// \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
18091809
// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
18101810
// \cgalParamNEnd

Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/stitch_borders.h

Lines changed: 101 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,46 @@ namespace internal {
6262
////// Helper structs
6363

6464
// Used to compare halfedges based on their geometry
65-
template <typename PolygonMesh, typename VertexPointMap>
65+
template <typename PolygonMesh, typename VertexPointMap, typename GeomTraits>
6666
struct Less_for_halfedge
6767
{
68+
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
6869
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
6970
typedef typename boost::property_traits<VertexPointMap>::reference Point;
7071

71-
Less_for_halfedge(const PolygonMesh& pmesh_, const VertexPointMap& vpm_)
72-
: pmesh(pmesh_), vpm(vpm_)
72+
Less_for_halfedge(const PolygonMesh& pmesh_, const VertexPointMap vpm_, const GeomTraits& gt_)
73+
: pmesh(pmesh_), vpm(vpm_), gt(gt_)
7374
{}
7475

7576
bool operator()(const halfedge_descriptor h1, const halfedge_descriptor h2) const
7677
{
77-
Point s1 = get(vpm,target(opposite(h1, pmesh), pmesh));
78-
Point t1 = get(vpm,target(h1, pmesh));
79-
Point s2 = get(vpm,target(opposite(h2, pmesh), pmesh));
80-
Point t2 = get(vpm,target(h2, pmesh));
78+
typename GeomTraits::Equal_3 equal = gt.equal_3_object();
79+
typename GeomTraits::Less_xyz_3 less = gt.less_xyz_3_object();
8180

82-
return (s1 < t1 ? std::make_pair(s1,t1) : std::make_pair(t1, s1))
83-
< (s2 < t2 ? std::make_pair(s2,t2) : std::make_pair(t2, s2));
81+
vertex_descriptor vm1 = source(h1, pmesh);
82+
vertex_descriptor vM1 = target(h1, pmesh);
83+
vertex_descriptor vm2 = source(h2, pmesh);
84+
vertex_descriptor vM2 = target(h2, pmesh);
85+
86+
if(less(get(vpm, vM1), get(vpm, vm1)))
87+
std::swap(vM1, vm1);
88+
if(less(get(vpm, vM2), get(vpm, vm2)))
89+
std::swap(vM2, vm2);
90+
91+
Point pm1 = get(vpm, vm1);
92+
Point pM1 = get(vpm, vM1);
93+
Point pm2 = get(vpm, vm2);
94+
Point pM2 = get(vpm, vM2);
95+
96+
if(equal(pm1, pm2))
97+
return less(pM1, pM2);
98+
99+
return less(pm1, pm2);
84100
}
85101

86102
const PolygonMesh& pmesh;
87-
const VertexPointMap& vpm;
103+
const VertexPointMap vpm;
104+
const GeomTraits& gt;
88105
};
89106

90107
// The following structs determine which of the two halfedges is kept when a pair is merged
@@ -320,15 +337,19 @@ template<typename Halfedge,
320337
typename Border_halfedge_map,
321338
typename Halfedge_pair,
322339
typename Manifold_halfedge_pair,
340+
typename Mesh,
323341
typename VPM,
324-
typename Mesh>
342+
typename GT>
325343
void fill_pairs(const Halfedge& he,
326344
Border_halfedge_map& border_halfedge_map,
327345
Halfedge_pair& halfedge_pairs,
328346
Manifold_halfedge_pair& manifold_halfedge_pairs,
347+
const Mesh& pmesh,
329348
VPM vpm,
330-
const Mesh& pmesh)
349+
const GT& gt)
331350
{
351+
typename GT::Equal_3 equal = gt.equal_3_object();
352+
332353
typename Border_halfedge_map::iterator set_it;
333354
bool insertion_ok;
334355
std::tie(set_it, insertion_ok) = border_halfedge_map.emplace(he, std::make_pair(1,0));
@@ -341,8 +362,8 @@ void fill_pairs(const Halfedge& he,
341362
const Halfedge other_he = set_it->first;
342363
set_it->second.second = halfedge_pairs.size(); // set the id of the pair in the vector
343364
halfedge_pairs.emplace_back(other_he, he);
344-
if(get(vpm, source(he,pmesh)) == get(vpm, target(other_he, pmesh)) &&
345-
get(vpm, target(he,pmesh)) == get(vpm, source(other_he, pmesh)))
365+
if(equal(get(vpm, source(he,pmesh)), get(vpm, target(other_he, pmesh))) &&
366+
equal(get(vpm, target(he,pmesh)), get(vpm, source(other_he, pmesh))))
346367
{
347368
// Even if the halfedges are compatible, refuse to stitch if that would break the graph
348369
if(face(opposite(he, pmesh), pmesh) == face(opposite(other_he, pmesh), pmesh))
@@ -383,17 +404,20 @@ OutputIterator collect_duplicated_stitchable_boundary_edges(const HalfedgeRange&
383404
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
384405
get_const_property_map(vertex_point, pmesh));
385406

407+
typedef typename GetGeomTraits<PolygonMesh, CGAL_PMP_NP_CLASS>::type GT;
408+
GT gt = choose_parameter<GT>(get_parameter(np, internal_np::geom_traits));
409+
386410
typedef CGAL::dynamic_face_property_t<int> Face_property_tag;
387411
typedef typename boost::property_map<PolygonMesh, Face_property_tag>::type Face_cc_map;
388412

389413
Face_cc_map cc;
390414
std::size_t num_cc = 0;
391415
std::vector<std::vector<halfedge_descriptor> > border_edges_per_cc;
392416

393-
typedef Less_for_halfedge<PolygonMesh, VPM> Less_hedge;
417+
typedef Less_for_halfedge<PolygonMesh, VPM, GT> Less_hedge;
394418
typedef std::map<halfedge_descriptor, std::pair<int, std::size_t>, Less_hedge> Border_halfedge_map;
395419

396-
Less_hedge less_hedge(pmesh, vpm);
420+
Less_hedge less_hedge(pmesh, vpm, gt);
397421
Border_halfedge_map border_halfedge_map(less_hedge);
398422

399423
std::vector<std::pair<halfedge_descriptor, halfedge_descriptor> > halfedge_pairs;
@@ -424,7 +448,7 @@ OutputIterator collect_duplicated_stitchable_boundary_edges(const HalfedgeRange&
424448
if(per_cc)
425449
border_edges_per_cc[get(cc, face(opposite(he, pmesh), pmesh))].push_back(he);
426450
else
427-
fill_pairs(he, border_halfedge_map, halfedge_pairs, manifold_halfedge_pairs, vpm, pmesh);
451+
fill_pairs(he, border_halfedge_map, halfedge_pairs, manifold_halfedge_pairs, pmesh, vpm, gt);
428452
}
429453

430454
if(per_cc)
@@ -439,7 +463,7 @@ OutputIterator collect_duplicated_stitchable_boundary_edges(const HalfedgeRange&
439463
{
440464
halfedge_descriptor he = border_edges_per_cc[i][j];
441465
fill_pairs(he, border_halfedge_map_in_cc, halfedge_pairs,
442-
manifold_halfedge_pairs, vpm, pmesh);
466+
manifold_halfedge_pairs, pmesh, vpm, gt);
443467
}
444468

445469
// put in `out` only manifold edges from the set of edges to stitch.
@@ -865,17 +889,21 @@ std::size_t stitch_halfedge_range_dispatcher(const HalfedgePairRange& to_stitch_
865889
// However, even if non-manifoldness exists within a loop, it is safe choice to stitch consecutive
866890
// stitchable halfedges
867891
template <typename HalfedgeRange,
892+
typename HalfedgeKeeper,
868893
typename PolygonMesh,
869894
typename VPM,
870-
typename HalfedgeKeeper>
895+
typename GT>
871896
std::size_t zip_boundary_cycle(typename boost::graph_traits<PolygonMesh>::halfedge_descriptor& bh,
872897
const HalfedgeRange& cycle_halfedges,
898+
const HalfedgeKeeper& hd_kpr,
873899
PolygonMesh& pmesh,
874900
const VPM vpm,
875-
const HalfedgeKeeper& hd_kpr)
901+
const GT& gt)
876902
{
877903
typedef typename boost::graph_traits<PolygonMesh>::halfedge_descriptor halfedge_descriptor;
878904

905+
typename GT::Equal_3 equal = gt.equal_3_object();
906+
879907
std::size_t stitched_boundary_cycles_n = 0;
880908

881909
// Zipping cannot change the topology of the hole so the maintenance is trivial
@@ -911,10 +939,11 @@ std::size_t zip_boundary_cycle(typename boost::graph_traits<PolygonMesh>::halfed
911939
do
912940
{
913941
halfedge_descriptor hnn = next(hn, pmesh);
914-
CGAL_assertion(get(vpm, target(hn, pmesh)) == get(vpm, source(hnn, pmesh)));
942+
CGAL_assertion(equal(get(vpm, target(hn, pmesh)), get(vpm, source(hnn, pmesh))));
915943

916-
if(get(vpm, source(hn, pmesh)) == get(vpm, target(hnn, pmesh)) &&
917-
!is_degenerate_edge(edge(hn, pmesh), pmesh, parameters::vertex_point_map(vpm)))
944+
if(equal(get(vpm, source(hn, pmesh)), get(vpm, target(hnn, pmesh))) &&
945+
!is_degenerate_edge(edge(hn, pmesh), pmesh,
946+
parameters::vertex_point_map(vpm).geom_traits(gt)))
918947
{
919948
if(unstitchable_halfedges.count(hn) == 0)
920949
{
@@ -980,8 +1009,9 @@ std::size_t zip_boundary_cycle(typename boost::graph_traits<PolygonMesh>::halfed
9801009
curr_hn = next(curr_hn, pmesh);
9811010

9821011
// check if the next two halfedges are not geometrically compatible
983-
if(get(vpm, source(curr_h, pmesh)) != get(vpm, target(curr_hn, pmesh)) ||
984-
is_degenerate_edge(edge(curr_hn, pmesh), pmesh, parameters::vertex_point_map(vpm)))
1012+
if(!equal(get(vpm, source(curr_h, pmesh)), get(vpm, target(curr_hn, pmesh))) ||
1013+
is_degenerate_edge(edge(curr_hn, pmesh), pmesh,
1014+
parameters::vertex_point_map(vpm).geom_traits(gt)))
9851015
{
9861016
bh = curr_hn;
9871017
break;
@@ -1046,6 +1076,9 @@ std::size_t stitch_boundary_cycle(const typename boost::graph_traits<PolygonMesh
10461076
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
10471077
get_const_property_map(vertex_point, pmesh));
10481078

1079+
typedef typename GetGeomTraits<PolygonMesh, CGAL_PMP_NP_CLASS>::type GT;
1080+
GT gt = choose_parameter<GT>(get_parameter(np, internal_np::geom_traits));
1081+
10491082
typedef typename internal_np::Lookup_named_param_def<internal_np::halfedges_keeper_t,
10501083
CGAL_PMP_NP_CLASS,
10511084
Default_halfedges_keeper<PolygonMesh> >::type Halfedge_keeper;
@@ -1058,7 +1091,7 @@ std::size_t stitch_boundary_cycle(const typename boost::graph_traits<PolygonMesh
10581091
for(halfedge_descriptor h : halfedges_around_face(bh, pmesh))
10591092
cycle_halfedges.push_back(h);
10601093

1061-
std::size_t res = internal::zip_boundary_cycle(bh, cycle_halfedges, pmesh, vpm, hd_kpr);
1094+
std::size_t res = internal::zip_boundary_cycle(bh, cycle_halfedges, hd_kpr, pmesh, vpm, gt);
10621095
if(bh == boost::graph_traits<PolygonMesh>::null_halfedge()) // stitched everything
10631096
{
10641097
cycle_reps_maintainer.remove_representative(bh);
@@ -1112,6 +1145,17 @@ std::size_t stitch_boundary_cycle(const typename boost::graph_traits<PolygonMesh
11121145
/// \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
11131146
/// must be available in `PolygonMesh`.}
11141147
/// \cgalParamNEnd
1148+
///
1149+
/// \cgalParamNBegin{geom_traits}
1150+
/// \cgalParamDescription{an instance of a geometric traits class}
1151+
/// \cgalParamType{The traits class must provide the nested type `Point_3`,
1152+
/// and the nested functors:
1153+
/// - `Less_xyz_3` to compare lexicographically two points
1154+
/// - `Equal_3` to check whether two points are identical.
1155+
/// For each functor `Foo`, a function `Foo foo_object()` must be provided.}
1156+
/// \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
1157+
/// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
1158+
/// \cgalParamNEnd
11151159
/// \cgalNamedParamsEnd
11161160
///
11171161
/// \returns the number of pairs of halfedges that were stitched.
@@ -1180,6 +1224,17 @@ std::size_t stitch_boundary_cycles(const BorderHalfedgeRange& boundary_cycle_rep
11801224
/// \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
11811225
/// must be available in `PolygonMesh`.}
11821226
/// \cgalParamNEnd
1227+
///
1228+
/// \cgalParamNBegin{geom_traits}
1229+
/// \cgalParamDescription{an instance of a geometric traits class}
1230+
/// \cgalParamType{The traits class must provide the nested type `Point_3`,
1231+
/// and the nested functors:
1232+
/// - `Less_xyz_3` to compare lexicographically two points
1233+
/// - `Equal_3` to check whether two points are identical.
1234+
/// For each functor `Foo`, a function `Foo foo_object()` must be provided.}
1235+
/// \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
1236+
/// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
1237+
/// \cgalParamNEnd
11831238
/// \cgalNamedParamsEnd
11841239
///
11851240
/// \returns the number of pairs of halfedges that were stitched.
@@ -1375,15 +1430,6 @@ std::size_t stitch_borders(const BorderHalfedgeRange& boundary_cycle_representat
13751430
/// \param np optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
13761431
///
13771432
/// \cgalNamedParamsBegin
1378-
/// \cgalParamNBegin{vertex_point_map}
1379-
/// \cgalParamDescription{a property map associating points to the vertices of `pmesh`}
1380-
/// \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<PolygonMesh>::%vertex_descriptor`
1381-
/// as key type and `%Point_3` as value type}
1382-
/// \cgalParamDefault{`boost::get(CGAL::vertex_point, pmesh)`}
1383-
/// \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
1384-
/// must be available in `PolygonMesh`.}
1385-
/// \cgalParamNEnd
1386-
///
13871433
/// \cgalParamNBegin{apply_per_connected_component}
13881434
/// \cgalParamDescription{specifies if the borders should only be stitched only within their own connected component.}
13891435
/// \cgalParamType{Boolean}
@@ -1396,6 +1442,26 @@ std::size_t stitch_borders(const BorderHalfedgeRange& boundary_cycle_representat
13961442
/// as key type and `std::size_t` as value type}
13971443
/// \cgalParamDefault{an automatically indexed internal map}
13981444
/// \cgalParamNEnd
1445+
///
1446+
/// \cgalParamNBegin{vertex_point_map}
1447+
/// \cgalParamDescription{a property map associating points to the vertices of `pmesh`}
1448+
/// \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<PolygonMesh>::%vertex_descriptor`
1449+
/// as key type and `%Point_3` as value type}
1450+
/// \cgalParamDefault{`boost::get(CGAL::vertex_point, pmesh)`}
1451+
/// \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
1452+
/// must be available in `PolygonMesh`.}
1453+
/// \cgalParamNEnd
1454+
///
1455+
/// \cgalParamNBegin{geom_traits}
1456+
/// \cgalParamDescription{an instance of a geometric traits class}
1457+
/// \cgalParamType{The traits class must provide the nested type `Point_3`,
1458+
/// and the nested functors:
1459+
/// - `Less_xyz_3` to compare lexicographically two points
1460+
/// - `Equal_3` to check whether two points are identical.
1461+
/// For each functor `Foo`, a function `Foo foo_object()` must be provided.}
1462+
/// \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
1463+
/// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
1464+
/// \cgalParamNEnd
13991465
/// \cgalNamedParamsEnd
14001466
///
14011467
/// \return the number of pairs of halfedges that were stitched.

0 commit comments

Comments
 (0)