From c380ad2fb663f287e09d64f34612a3bafc1da55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Valque?= Date: Thu, 16 Oct 2025 15:14:42 +0200 Subject: [PATCH] Snap of polygons --- .../include/CGAL/Float_snap_rounding_2.h | 100 ++++++++--------- .../test_float_snap_rounding_2.cpp | 103 ++++++------------ 2 files changed, 79 insertions(+), 124 deletions(-) diff --git a/Snap_rounding_2/include/CGAL/Float_snap_rounding_2.h b/Snap_rounding_2/include/CGAL/Float_snap_rounding_2.h index dc2ff684d8a..e535fb0c6c7 100644 --- a/Snap_rounding_2/include/CGAL/Float_snap_rounding_2.h +++ b/Snap_rounding_2/include/CGAL/Float_snap_rounding_2.h @@ -476,12 +476,12 @@ typename OutputContainer::iterator compute_snapped_subcurves_2(InputIterator using I2E = typename Traits::Converter_in; using E2O = typename Traits::Converter_out; using VectorIterator = typename std::vector::iterator; - I2E converter_to_exact=traits.converter_to_exact_object(); - E2O converter_from_exact=traits.converter_from_exact_object(); + I2E to_exact=traits.converter_to_exact_object(); + E2O from_exact=traits.converter_from_exact_object(); std::vector convert_input; for(InputIterator it=input_begin; it!=input_end; ++it) - convert_input.push_back(Segment_2(converter_to_exact(*it))); + convert_input.push_back(Segment_2(to_exact(*it))); std::vector segs; #ifdef DOUBLE_2D_SNAP_VERBOSE std::cout << "Solved intersections" << std::endl; @@ -537,7 +537,7 @@ typename OutputContainer::iterator compute_snapped_subcurves_2(InputIterator set_out_segs.emplace((std::min)(poly[i-1],poly[i]),(std::max)(poly[i-1],poly[i])); } for(auto &pair: set_out_segs){ - output.emplace_back(converter_from_exact(pts[pair.first]), converter_from_exact(pts[pair.second])); + output.emplace_back(from_exact(pts[pair.first]), from_exact(pts[pair.second])); assert(pts[pair.first]!=pts[pair.second]); } @@ -547,71 +547,67 @@ typename OutputContainer::iterator compute_snapped_subcurves_2(InputIterator /** * ingroup * -* Given a range of segments, compute rounded subsegments that are pairwise disjoint in their interior, as induced by the input curves. +* Given a Polygon_2, compute rounded segments that are pairwise disjoint in their interior, as induced by the input polygon. +* The output is guarantee to be a Polygon but may present pinched section. * * @tparam Concurrency_tag That template parameter enables to choose whether the algorithm is to be run in * parallel, if CGAL::Parallel_tag is specified and CGAL has been linked with the Intel TBB library, or sequentially, if CGAL::Sequential_tag - the default value - is specified. * @tparam InputIterator iterator of a segment range * @tparam OutputContainer inserter of a segment range * @tparam The exact kernel needed for computation (Epeck by default) +* +* @warning The convex property is not necessarly preserved */ -template ::value_type>>::Kernel> > -typename OutputContainer::iterator snap_polygons_2(InputIterator input_begin, - InputIterator input_end, - OutputContainer& output, - const Traits& traits=Traits()) +template ::Kernel> > +void snap_polygons_2(const Polygon_2 &P, + Polygon_2 &out, + const Traits& traits=Traits(), + bool check_duplicates = false) { using Point_2 = typename Traits::Point_2; using Segment_2 = typename Traits::Segment_2; using I2E = typename Traits::Converter_in; using E2O = typename Traits::Converter_out; using VectorIterator = typename std::vector::iterator; - I2E converter_to_exact=traits.converter_to_exact_object(); - E2O converter_from_exact=traits.converter_from_exact_object(); - - std::vector convert_input; - for(InputIterator it=input_begin; it!=input_end; ++it) - convert_input.push_back(Segment_2(converter_to_exact(*it))); - std::vector segs; -#ifdef DOUBLE_2D_SNAP_VERBOSE - std::cout << "Solved intersections" << std::endl; -#endif - compute_subcurves(convert_input.begin(), convert_input.end(), std::back_inserter(segs)); + I2E to_exact=traits.converter_to_exact_object(); + E2O from_exact=traits.converter_from_exact_object(); #ifdef DOUBLE_2D_SNAP_VERBOSE std::cout << "Change format to range of points and indexes" << std::endl; #endif - std::set unique_point_set; - std::map point_to_index; std::vector pts; std::vector< std::vector< std::size_t> > polylines; - // Transform range of the segments in the range of points and polyline of indexes - for(VectorIterator it=segs.begin(); it!=segs.end(); ++it) - { - const Point_2& p1 = it->source(); - const Point_2& p2 = it->target(); + if(check_duplicates){ + std::set unique_point_set; + std::map point_to_index; - if (unique_point_set.find(p1) == unique_point_set.end()) { - unique_point_set.insert(p1); - pts.push_back(p1); - point_to_index[p1] = pts.size() - 1; + // Transform the polygon in a range of points and polylines of indexes + for(const typename Polygon_2::Point_2 &p_: P.vertices()) + { + Point_2 p=to_exact(p_); + if (unique_point_set.find(p) == unique_point_set.end()) { + unique_point_set.insert(p); + pts.push_back(p); + point_to_index[p] = pts.size() - 1; + } } - if (unique_point_set.find(p2) == unique_point_set.end()) { - unique_point_set.insert(p2); - pts.push_back(p2); - point_to_index[p2] = pts.size() - 1; + + for(const typename Polygon_2::Segment_2 &s: P.edges()){ + Point_2 p1=to_exact(s.source()); + Point_2 p2=to_exact(s.target()); + std::size_t index1 = point_to_index[p1]; + std::size_t index2 = point_to_index[p2]; + polylines.push_back({index1, index2}); } + } else { + for(const typename Polygon_2::Point_2 &p: P.vertices()) + pts.push_back(to_exact(p)); + for(size_t i=0; isource()]; - std::size_t index2 = point_to_index[it->target()]; - polylines.push_back({index1, index2}); - } - - // Main algorithm double_snap_rounding_2_disjoint(pts, polylines, traits); @@ -620,20 +616,14 @@ typename OutputContainer::iterator snap_polygons_2(InputIterator input_begin, #endif // Output a range of segments while removing duplicate ones - std::set< std::pair > set_out_segs; - output.clear(); - for(auto &poly: polylines){ + out.clear(); + for(auto &poly: polylines) for(std::size_t i=1; i #include @@ -129,69 +127,47 @@ void test_almost_indentical_segments(CGAL::Random &r, size_t nb_segments, Vector } void test_iterative_square_intersection(CGAL::Random &r, size_t nb_iterations){ - auto add_random_rotated_square=[&](std::vector &segs){ + auto random_rotated_square=[&](){ double theta=r.get_double(0, CGAL_PI/2); - double cos_t = std::cos(theta); - double sin_t = std::sin(theta); - Point_2 a( cos_t, sin_t); - Point_2 b( sin_t,-cos_t); - Point_2 c(-cos_t,-sin_t); - Point_2 d(-sin_t, cos_t); - segs.emplace_back(a,b); - segs.emplace_back(b,c); - segs.emplace_back(c,d); - segs.emplace_back(d,a); +#ifdef BENCH_AND_VERBOSE_FLOAT_SNAP_ROUNDING_2 + std::cout << "Angle: " << theta << std::endl; +#endif + FT cos_t(std::cos(theta)); + FT sin_t(std::sin(theta)); + Polygon_2 P; + P.push_back(Point_2( cos_t, sin_t)); + P.push_back(Point_2(-sin_t, cos_t)); + P.push_back(Point_2(-cos_t,-sin_t)); + P.push_back(Point_2( sin_t,-cos_t)); + return P; }; - std::vector segs; - std::vector out; - std::vector arr_segs; + Polygon_2 scene=random_rotated_square(); + Polygon_2 snap_scene; + Pwh_vec_2 out_intersection; - CGAL::Real_timer t; for(size_t i=0; i segs; - FT e(std::pow(2, -60)); - segs.emplace_back(Point_2(0, 0), Point_2(1, 1)); - segs.emplace_back(Point_2(0.5+e, 0.5), Point_2(1, -1)); - segs.emplace_back(Point_2(0.5-e, 0.5), Point_2(-1, 3)); - - test(segs); -} - int main(int argc,char *argv[]) { CGAL::Random rp; CGAL::Random r(argc==1?rp.get_seed():std::stoi(argv[1])); std::cout << "random seed = " << r.get_seed() << std::endl; std::cout << std::setprecision(17); - test_box_intersection(); fix_test(); // test_fully_random(r,1000); // test_multi_almost_indentical_segments(r,100); - // test_iterative_square_intersection(r,500); + test_iterative_square_intersection(r,2000); return(0); }