@@ -44,15 +44,36 @@ namespace CGAL {
4444namespace Polygon_mesh_processing {
4545namespace 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+
4765template <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
116147template <class Kernel ,
@@ -122,59 +153,52 @@ template <class Kernel>
122153class 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
141172public:
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
157189template <class Kernel >
158190class 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