Skip to content

Commit a20fff9

Browse files
committed
WIP: handle degenerate cases
1 parent a54b342 commit a20fff9

File tree

1 file changed

+114
-86
lines changed

1 file changed

+114
-86
lines changed

Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polyline_snapping.h

Lines changed: 114 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,36 @@ namespace CGAL {
4444
namespace Polygon_mesh_processing{
4545
namespace internal {
4646

47+
template <typename Kernel>
48+
struct Snapping_result
49+
{
50+
using Point_3 = typename Kernel::Point_3;
51+
using Segment_3 = typename Kernel::Segment_3;
52+
enum Type { EMPTY, POINT, SEGMENT };
53+
54+
Type type;
55+
boost::variant<Point_3, Segment_3> first;
56+
boost::variant<Point_3, Segment_3> second;
57+
58+
Snapping_result() : type (EMPTY) { }
59+
Snapping_result (const Point_3& first, const Point_3& second)
60+
: type (POINT), first (first), second (second) { }
61+
Snapping_result (const Segment_3& first, const Segment_3& second)
62+
: type (SEGMENT), first (first), second (second) { }
63+
};
64+
4765
template <typename Exact_kernel>
48-
bool exact_snapping (const typename Exact_kernel::Segment_3& s0,
49-
const typename Exact_kernel::Segment_3& s1,
50-
typename Exact_kernel::Point_3& result)
66+
Snapping_result<Exact_kernel>
67+
exact_snapping (const typename Exact_kernel::Segment_3& s0,
68+
const typename Exact_kernel::Segment_3& s1)
5169
{
52-
typedef typename Exact_kernel::Point_3 Point_3;
53-
typedef typename Exact_kernel::Segment_3 Segment_3;
54-
typedef typename Exact_kernel::Vector_3 Vector_3;
55-
typedef typename Exact_kernel::Plane_3 Plane_3;
70+
using Point_3 = typename Exact_kernel::Point_3;
71+
using Segment_3 = typename Exact_kernel::Segment_3;
72+
using Line_3 = typename Exact_kernel::Line_3;
73+
using Vector_3 = typename Exact_kernel::Vector_3;
74+
using Plane_3 = typename Exact_kernel::Plane_3;
75+
using FT = typename Exact_kernel::FT;
76+
using Result = Snapping_result<Exact_kernel>;
5677

5778
CGAL_assertion (s0.source() != s0.target());
5879
CGAL_assertion (s1.source() != s1.target());
@@ -64,7 +85,32 @@ bool exact_snapping (const typename Exact_kernel::Segment_3& s0,
6485
// Collinear segments
6586
if (normal == CGAL::NULL_VECTOR)
6687
{
67-
return false;
88+
Point_3 proj0 = v1.supporting_line().projection(s0.source());
89+
Point_3 med = midpoint(s0.source(), proj0);
90+
Line_3 support (med, v0);
91+
Vector ref (med, support.projection(s0.target()));
92+
93+
std::vector<std::pair<FT, Point_3>> points_along_line;
94+
95+
auto create_projection = [&](const Point_3& p)
96+
{
97+
Point_3 proj = support.projection(p);
98+
Vector vec (med, proj);
99+
FT position = vec * ref;
100+
points_along_line.emplace_back(position, proj);
101+
};
102+
create_projection (s0.source());
103+
create_projection (s0.target());
104+
create_projection (s1.source());
105+
create_projection (s1.target());
106+
107+
std::sort (points_along_line.begin(), points_along_line.end(),
108+
[](const auto& a, const auto& b) -> bool
109+
{
110+
return a.first < b.first;
111+
});
112+
113+
return Result();
68114
}
69115

70116
Plane_3 plane0 (s0.source(), normal);
@@ -78,39 +124,24 @@ bool exact_snapping (const typename Exact_kernel::Segment_3& s0,
78124
CGAL_assertion (s0proj.source() != s0proj.target());
79125
CGAL_assertion (s1proj.source() != s1proj.target());
80126

81-
if (!CGAL::do_intersect (s0, s1proj) ||
82-
!CGAL::do_intersect (s1, s0proj))
83-
return false;
84-
85-
Point_3 p0, p1;
86-
87127
typename std::result_of<typename Exact_kernel::Intersect_3(Segment_3, Segment_3)>::type
88128
intersection0 = intersection(s0, s1proj);
89129
if (!intersection0)
90-
return false;
91-
92-
if (const Point_3* p = boost::get<Point_3>(&*intersection0))
93-
p0 = *p;
94-
else // Coplanar segments
95-
{
96-
return false;
97-
}
130+
return Result();
98131

99132
typename std::result_of<typename Exact_kernel::Intersect_3(Segment_3, Segment_3)>::type
100133
intersection1 = intersection(s1, s0proj);
101-
if (!intersection1)
102-
return false;
134+
CGAL_assertion (bool(intersection1));
103135

104-
if (const Point_3* p = boost::get<Point_3>(&*intersection1))
105-
p1 = *p;
106-
else // Coplanar segments
136+
if (const Point_3* p0 = boost::get<Point_3>(&*intersection0))
107137
{
108-
return false;
138+
const Point_3* p1 = boost::get<Point_3>(&*intersection1);
139+
CGAL_assertion(p1 != nullptr);
140+
return Result (*p0, *p1);
109141
}
110142

111-
result = CGAL::midpoint (p0, p1);
112-
113-
return true;
143+
// else coplanar segments
144+
return Result();
114145
}
115146

116147
template <class Kernel,
@@ -122,59 +153,52 @@ template <class Kernel>
122153
class Exact_snapping<Kernel,false>
123154
{
124155
//typedefs
125-
typedef Kernel Input_kernel;
126-
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel;
127-
typedef CGAL::Cartesian_converter<Exact_kernel, Input_kernel> Exact_to_inexact;
128-
typedef CGAL::Cartesian_converter<Input_kernel, Exact_kernel> Inexact_to_exact;
129-
130-
typedef typename Input_kernel::Point_3 Inexact_point_3;
131-
typedef typename Input_kernel::Line_3 Inexact_line_3;
132-
typedef typename Input_kernel::Segment_3 Inexact_segment_3;
133-
typedef typename Exact_kernel::Point_3 Exact_point_3;
134-
typedef typename Exact_kernel::Line_3 Exact_line_3;
135-
typedef typename Exact_kernel::Segment_3 Exact_segment_3;
136-
137-
Exact_kernel ek;
156+
using Exact_kernel = Exact_predicates_exact_constructions_kernel;
157+
using Exact_segment_3 = typename Exact_kernel::Segment_3;
158+
using Exact_point_3 = typename Exact_kernel::Point_3;
159+
using Exact_result = Snapping_result<Exact_kernel>;
160+
161+
using Inexact_kernel = Kernel;
162+
using Inexact_segment_3 = typename Inexact_kernel::Segment_3;
163+
using Inexact_point_3 = typename Inexact_kernel::Point_3;
164+
using Inexact_result = Snapping_result<Inexact_kernel>;
165+
166+
using Exact_to_inexact = Cartesian_converter<Exact_kernel, Inexact_kernel>;
167+
using Inexact_to_exact = Cartesian_converter<Inexact_kernel, Exact_kernel>;
168+
138169
Exact_to_inexact to_inexact;
139170
Inexact_to_exact to_exact;
140171

141172
public:
142173

143-
std::pair<Inexact_point_3, bool> intersection (const Inexact_segment_3& s0, const Inexact_segment_3& s1) const
174+
Inexact_result intersection (const Inexact_segment_3& s0, const Inexact_segment_3& s1) const
144175
{
145-
Exact_segment_3 exact_s0 = to_exact(s0);
146-
Exact_segment_3 exact_s1 = to_exact(s1);
147-
Exact_point_3 result;
148-
149-
if (exact_snapping<Exact_kernel> (exact_s0, exact_s1, result))
150-
return std::make_pair (to_inexact (result), true);
151-
152-
return std::make_pair (Inexact_point_3(), false);
176+
Exact_result result = exact_snapping<Exact_kernel> (to_exact(s0), to_exact(s1));
177+
if (result.type == Exact_result::EMPTY)
178+
return Inexact_result();
179+
if (result.type == Exact_result::POINT)
180+
return Inexact_result (to_inexact (get<const Exact_point_3&>(result.first)),
181+
to_inexact (get<const Exact_point_3&>(result.second)));
182+
// else Segment
183+
return Inexact_result (to_inexact (get<const Exact_segment_3&>(result.first)),
184+
to_inexact (get<const Exact_segment_3&>(result.second)));
153185
}
154186

155187
};
156188

157189
template <class Kernel>
158190
class Exact_snapping<Kernel,true>
159191
{
160-
//typedefs
161-
typedef typename Kernel::Point_3 Point_3;
162-
typedef typename Kernel::Line_3 Line_3;
163-
typedef typename Kernel::Segment_3 Segment_3;
164-
public:
165-
166-
Exact_snapping()
167-
{
192+
using Segment_3 = typename Kernel::Segment_3;
193+
using Point_3 = typename Kernel::Point_3;
194+
using Result = Snapping_result<Kernel>;
168195

169-
}
196+
public:
170197

171-
std::pair<Point_3, bool> intersection (const Segment_3& s0, const Segment_3& s1) const
198+
Result intersection (const Segment_3& s0, const Segment_3& s1) const
172199
{
173-
Point_3 result;
174-
bool out = exact_snapping<Kernel> (s0, s1, result);
175-
return std::make_pair (result, out);
200+
return exact_snapping<Kernel>(s0,s1);
176201
}
177-
178202
};
179203

180204
}// namespace internal
@@ -354,6 +378,7 @@ void polyline_snapping (Graph& graph, PointMap point_map, double tolerance)
354378
using Kernel = typename Kernel_traits<Point_3>::Kernel;
355379
using Segment_3 = typename Kernel::Segment_3;
356380
using FT = typename Kernel::FT;
381+
using Result = internal::Snapping_result<Kernel>;
357382

358383
using vertex_descriptor = typename boost::graph_traits<Graph>::vertex_descriptor;
359384
using edge_descriptor = typename boost::graph_traits<Graph>::edge_descriptor;
@@ -412,27 +437,30 @@ void polyline_snapping (Graph& graph, PointMap point_map, double tolerance)
412437
return;
413438

414439
// Compute exact snapping point
415-
Point_3 new_point;
416-
bool okay;
417-
std::tie (new_point, okay) = exact_snapping.intersection (sa, sb);
418-
if (!okay)
440+
Result snapping = exact_snapping.intersection (sa, sb);
441+
if (snapping.type == Result::EMPTY)
419442
return;
420443

421-
// Create new vertex
422-
vertex_descriptor vd = add_vertex(graph);
423-
put (point_map, vd, new_point);
424-
425-
// Compute barycentric coord along each segment
426-
FT ba = approximate_sqrt (squared_distance (sa.source(), sa.supporting_line().projection(new_point))
427-
/ sa.squared_length());
428-
FT bb = approximate_sqrt (squared_distance (sb.source(), sb.supporting_line().projection(new_point))
429-
/ sb.squared_length());
430-
431-
// Store relative position of new vertex on edges
432-
auto ma = new_vertices.insert (std::make_pair(ea, std::vector<Vertex_position>()));
433-
auto mb = new_vertices.insert (std::make_pair(eb, std::vector<Vertex_position>()));
434-
ma.first->second.emplace_back (ba, vd);
435-
mb.first->second.emplace_back (bb, vd);
444+
if (snapping.type == Result::POINT)
445+
{
446+
const Point_3& a = get<const Point_3&>(snapping.first);
447+
const Point_3& b = get<const Point_3&>(snapping.second);
448+
Point_3 new_point = midpoint(a,b);
449+
450+
// Create new vertex
451+
vertex_descriptor vd = add_vertex(graph);
452+
put (point_map, vd, new_point);
453+
454+
// Compute barycentric coord along each segment
455+
FT ba = approximate_sqrt (squared_distance (sa.source(), a) / sa.squared_length());
456+
FT bb = approximate_sqrt (squared_distance (sb.source(), b) / sb.squared_length());
457+
458+
// Store relative position of new vertex on edges
459+
auto ma = new_vertices.insert (std::make_pair(ea, std::vector<Vertex_position>()));
460+
auto mb = new_vertices.insert (std::make_pair(eb, std::vector<Vertex_position>()));
461+
ma.first->second.emplace_back (ba, vd);
462+
mb.first->second.emplace_back (bb, vd);
463+
}
436464
},
437465
cutoff);
438466

0 commit comments

Comments
 (0)