#include // needed for the LONGNAME flag #include #ifndef CGAL_PLANAR_MAP_2 #include #endif //#include #include #include #include #include #include #include #include #include #include #include // Quotient is included anyway, because it is used to read // data files. Quotient can read both integers and fractions. // leda rational will only read fractions. #include #include #include #include #include // Making sure test doesn't fail if LEDA is not installed #if ! defined(CGAL_USE_LEDA) && \ (CGAL_ARR_TEST_TRAITS == CGAL_POLYLINE_LEDA_TRAITS || \ CGAL_ARR_TEST_TRAITS == CGAL_SEGMENT_LEDA_TRAITS || \ CGAL_ARR_TEST_TRAITS == CGAL_SEGMENT_CIRCLE_TRAITS) int main(int argc, char* argv[]) { std::cout << "A try to run test with LEDA traits but LEDA is not installed."; std::cout << std::endl; std::cout << "Test is not performed."; std::cout << std::endl; return 0; } #else #include #include #include // Choose traits #include // Quotient is included anyway, because it is used to read // data files. Quotient can read both integers and fractions. // leda rational will only read fractions. //nclude class Boolean_operations_test { struct Face_with_counter : public CGAL::Arr_2_face_base { Face_with_counter() : CGAL::Arr_2_face_base(), counter(-1) {} int counter; }; public: //typedef CGAL::Quotient NT; typedef leda_rational NT; typedef CGAL::Cartesian R; typedef CGAL::Arr_segment_traits_2 Traits; typedef Traits::Point_2 Point; typedef Traits::X_monotone_curve_2 X_curve; typedef Traits::Curve_2 Curve; typedef CGAL::Polygon_traits_2 Polygon_traits; typedef std::list Polygon_Container; typedef CGAL::Polygon_2 Polygon; typedef std::list Polygon_list; typedef CGAL::Bop_default_dcel Dcel; typedef CGAL::Planar_map_2 Planar_map; typedef CGAL::Planar_map_with_intersections_2 Pmwx; typedef CGAL::Map_overlay_default_notifier MapOverlay_change_notification; typedef CGAL::Map_overlay_2 MapOverlay; typedef CGAL::Boolean_operations_2 Bops; typedef Planar_map::Ccb_halfedge_circulator Ccb_halfedge_circulator; typedef Planar_map::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; typedef Planar_map::Face_handle Face_handle; typedef Planar_map::Vertex_iterator Vertex_iterator; typedef Planar_map::Face_iterator Face_iterator; typedef Planar_map::Holes_iterator Holes_iterator; typedef Planar_map::Holes_const_iterator Holes_const_iterator; typedef Planar_map::Face Face; typedef Planar_map::Halfedge Halfedge; typedef Planar_map::Vertex Vertex; typedef Bops::Faces_container Faces_container; typedef Bops::Halfedges_container Halfedges_container; typedef Bops::Vertices_container Vertices_container; //typedef CGAL::Planar_map_with_intersections_2 Pmwx; typedef CGAL::Arr_base_node Base_node; typedef CGAL::Pm_dcel, CGAL::Arr_2_halfedge_base, Face_with_counter > Arr_Dcel; typedef CGAL::Arrangement_2 Arrangement; typedef CGAL::Pm_walk_along_line_point_location PmWalkPL; typedef CGAL::Pm_naive_point_location PmNaivePL; private: template class less_xy { public: inline bool operator()(const Point& p1, const Point& p2) const { return CGAL::compare_lexicographically_xy(p1,p2) == CGAL::SMALLER; } }; //------------------------------------ Boolean operations functions. //generalized face_diff function, to acount for overlaps. int face_diff (Arrangement::Ccb_halfedge_circulator circ) { Traits t; int diff = 0; Arrangement::Overlap_circulator oc = circ->overlap_edges(); do { if (circ->source()->point() == t.curve_source(oc->curve()) ) diff--; //we're inside, going outside else diff++; } while (++oc != circ->overlap_edges()); return diff; } // covering_DFS will compute for each face in how many polygons it is. // It is a recursive DFS function and will be called with the unbounded // face after its counter has been initialized to 0. void covering_DFS(Arrangement::Face_handle f) { Arrangement::Ccb_halfedge_circulator start,circ; // Do a recursive step for all neighbours, if any exists. if (f->does_outer_ccb_exist()) { start = circ = f->outer_ccb(); do { if (circ->twin()->face()->counter < 0) { int diff = face_diff(circ); circ->twin()->face()->counter = (f->counter + diff); covering_DFS(circ->twin()->face()); } } while (++circ != start); } // Do a recursive step for all holes, if any exists. Arrangement::Holes_iterator hit = f->holes_begin(); for (; Arrangement::Holes_iterator(hit)!= Arrangement::Holes_iterator(f->holes_end()); ++hit) { start = circ = (*hit); do { if (circ->twin()->face()->counter < 0) { int diff = face_diff(circ); circ->twin()->face()->counter = (f->counter + diff); covering_DFS(circ->twin()->face()); } } while (++circ != start); } } // Construct the arrangement that will use for calculating the intersection. void insert_polygons(Arrangement &arr, Polygon_list &in_poly_list) { Polygon::Edge_const_iterator it; Arrangement::Curve_iterator ci; Polygon_list::iterator plit; // for each polygon in list for (plit = in_poly_list.begin(); plit != in_poly_list.end(); ++plit) { // Make sure polygons are oriented counterclockwise // to satisfy assumption in DFS function if ( ! plit->is_counterclockwise_oriented()) plit->reverse_orientation(); // insert polygon to arrangement for (it = plit->edges_begin(); it != plit->edges_end(); ++it) { ci = arr.insert(*it); } } } /* // Convert faces of the arrangement that are in the intersection // to polygons. void polygons_from_faces(Arrangement& arr, std::list& face_it_list, Polygon_list& poly_list) { std::list::iterator lit; //Pmwx::Ccb_halfedge_circulator cc; Polygon poly; for (lit = face_it_list.begin(); lit != face_it_list.end(); ++lit) { poly.erase(poly.vertices_begin(), poly.vertices_end()); Arrangement::Ccb_halfedge_circulator cc=(*lit)->outer_ccb(); do { poly.push_back(cc->curve().source()); } while (++cc != (*lit)->outer_ccb()); poly_list.push_back(poly); } }*/ // performs the extraction of data out of the processed arrangement // if covering = 0, will perform union // otherwise, if there are n polygons in the arrangement and covering == n // then will perform intersection template void get_faces_with_covering(OutputIterator faces, Arrangement& arr, int covering) { Arrangement::Face_handle uf = arr.unbounded_face(); uf->counter = 0; covering_DFS(uf); //"collecting" the union boundary faces. for(Arrangement::Face_iterator fit = arr.faces_begin(); fit!=arr.faces_end(); ++fit) { // if the face is covered by 'covering' if (fit->counter == covering) { //unions.push_back(fit); *faces = fit; ++faces; } } } template void get_points_below_vertex_with_covering(InputIterator1 points_begin, InputIterator1 points_end, InputIterator2 polygons_begin, InputIterator2 polygons_end, Container& points, int covering) { for (InputIterator1 p_iter=points_begin; p_iter!= points_end; ++p_iter){ int num_vertices_above=0; for (InputIterator2 poly_iter=polygons_begin; poly_iter!=polygons_end; ++poly_iter){ bool found=false; for (Polygon::Vertex_const_iterator v_iter=poly_iter->vertices_begin(); v_iter != poly_iter->vertices_end() && !found; ++v_iter){ // *e_iter is CGAL Segment. if (*v_iter == *p_iter) found=true; } if (found) ++num_vertices_above; } //cout << *p_iter <<" is below "<< num_vertices_above <<" vertices" //< void get_points_below_edge_with_covering(InputIterator1 points_begin, InputIterator1 points_end, InputIterator2 polygons_begin, InputIterator2 polygons_end, Container& points, int covering) { Traits traits; for (InputIterator1 p_iter=points_begin; p_iter!= points_end; ++p_iter){ int num_edges_above=0; for (InputIterator2 poly_iter=polygons_begin; poly_iter!=polygons_end; ++poly_iter){ bool found=false; for (Polygon::Edge_const_iterator e_iter=poly_iter->edges_begin(); e_iter != poly_iter->edges_end() && !found; ++e_iter){ // *e_iter is CGAL Segment. Curve cv(*e_iter); if (traits.curve_compare_y_at_x(cv,*p_iter) == Traits::ON_CURVE) found=true; } if (found) ++num_edges_above; } //cout << *p_iter <<" is below "<< num_edges_above <<" edges"< void get_points_below_halfedge(InputIterator halfedges_begin, InputIterator halfedges_end, Container& points) { InputIterator iter=halfdges_begin; for ( ;halfedge_iter!=halfedge_end; ++halfedge_iter, ++halfedge_iter){ points.insert(halfedge_iter->source()->point()); points.insert(halfedge_iter->target()->point()); } } // we can use this function, instead of computing exact covering, since // there are not isolated vertices in our structures. Hence if a vertex is // below a face - it has to be connected to at least one edge. template void get_points_below_faces(InputIterator1 points_begin, InputIterator1 points_end, InputIterator2 faces_begin, InputIterator2 faces_end, Container& points) { std::set > endpoints(points_begin, points_end); for (InputIterator2 face_iter=faces_begin; face_iter!=faces_end; ++face_iter){ if ((*face_iter)->does_outer_ccb_exist()){ Arrangement::Ccb_halfedge_circulator circ=(*face_iter)->outer_ccb(); do { // inserting the point only if it's an end point. if (endpoints.find(circ->source()->point()) != endpoints.end()) points.insert(circ->source()->point()); } while (++circ != (*face_iter)->outer_ccb()); } Arrangement::Holes_iterator hit = (*face_iter)->holes_begin(); for ( ;hit!= (*face_iter)->holes_end(); ++hit) { Arrangement::Ccb_halfedge_circulator circ = (*hit); do { if (endpoints.find(circ->source()->point()) != endpoints.end()) points.insert(circ->source()->point()); } while (++circ != *hit); } } } // This function is written for the symmetric difference. // the two former functions: get_points_below_vertex_with_covering and // get_points_below_edge_with_covering could have return a point inside a // polygon since this check was not perfromed. Here we clean such points. template void remove_points_below_faces(InputIterator polygons_begin, InputIterator polygons_end, Container& points) { for (typename Container::iterator p_iter=points.begin(); p_iter!=points.end(); ){ InputIterator poly_iter; for (poly_iter=polygons_begin; poly_iter!=polygons_end; ++poly_iter){ if (poly_iter->has_on_bounded_side(*p_iter)){ points.erase(p_iter++); break; } } if (poly_iter==polygons_end) ++p_iter; } } template void get_vertices_with_covering(InputIterator1 polygons_begin, InputIterator1 polygons_end, InputIterator2 faces_begin, InputIterator2 faces_end, OutputIterator vertices, const Arrangement& arr, int covering) { std::set > endpoints; std::set > covering_endpoints; //std::set > common_endpoints; // holds equal endpoints from different polygons. std::list intersections; // inserting to common points the endpoints which have covering number of // vertices above. for (InputIterator1 poly_iter=polygons_begin; poly_iter != polygons_end; ++poly_iter){ for (Polygon::Vertex_iterator v_iter=poly_iter->vertices_begin(); v_iter!=poly_iter->vertices_end(); ++v_iter) endpoints.insert(*v_iter); } get_points_below_vertex_with_covering(endpoints.begin(),endpoints.end(), polygons_begin,polygons_end, covering_endpoints,covering); get_points_below_edge_with_covering(endpoints.begin(),endpoints.end(), polygons_begin,polygons_end, covering_endpoints,covering); for (Arrangement::Vertex_const_iterator v_iter=arr.vertices_begin(); v_iter!=arr.vertices_end(); ++v_iter){ if (endpoints.find(v_iter->point()) == endpoints.end()) // intersection intersections.push_back(v_iter->point()); } if (covering > 1){ // intersection or union. get_points_below_faces(endpoints.begin(),endpoints.end(), faces_begin, faces_end, covering_endpoints); std::copy(covering_endpoints.begin(),covering_endpoints.end(),vertices); std::copy(intersections.begin(),intersections.end(),vertices); } else if (covering == 1) { // symmetric difference. remove_points_below_faces(polygons_begin,polygons_end,covering_endpoints); std::copy(covering_endpoints.begin(),covering_endpoints.end(),vertices); } } // The interface for an intersection function template void intersect_polygons(Arrangement arr, OutputIterator faces) { //insert_polygons(arr, in_poly_list); // faces with a covering two are faces that are in the intersection // of the two polygons. //get_faces_with_covering(arr, faces, in_poly_list.size()); //polygons_from_faces(arr, face_it_list, out_poly_list); //if (begin == faces) return 0; else return 1; } //----------------------------------- compating Planar_map features class Equal_Halfedge { public: Equal_Halfedge(const Arrangement::Halfedge& h) : h_(h) {} bool operator()(const Halfedge& halfedge) const { Traits traits; /* // for debugging! cout<<"("<point() == halfedge.source()->point() && h_.target()->point() == halfedge.target()->point()); } private: const Arrangement::Halfedge& h_; }; class Equal_Ccb { public: Equal_Ccb(Arrangement::Ccb_halfedge_const_circulator outer_ccb1_) : outer_ccb1(outer_ccb1_) {} bool operator()(Ccb_halfedge_const_circulator outer_ccb2) const { Arrangement::Ccb_halfedge_const_circulator circ1=outer_ccb1; Ccb_halfedge_const_circulator circ2=outer_ccb2; unsigned int size1=0,size2=0; do { // for debugging! /*cout<<"("<curve().source().x())<<","<< CGAL::to_double(circ1->curve().source().y())<<") "; cout<<"("<curve().target().x())<<","<< CGAL::to_double(circ1->curve().target().y())<<") "<curve().source().x())<<","<< CGAL::to_double(circ2->curve().source().y())<<") "; cout<<"("<curve().target().x())<<","<< CGAL::to_double(circ2->curve().target().y())<<") "< void compare_vertices(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2) { // for debugging: cout<<"vertices sizes:"<x()) << " "<< // CGAL::to_double(iter1->y()) << endl; //for (InputIterator2 iter2=begin2; iter2!=end2; ++iter2) // cout << CGAL::to_double(iter2->x()) << " "<< // CGAL::to_double(iter2->y()) << endl; // end degugging. CGAL_assertion(std::distance(begin1,end1) == std::distance(begin2,end2)); for (InputIterator1 iter1=begin1; iter1!= end1; ++iter1) CGAL_assertion(std::find(begin2,end2,*iter1) != end2); } template void compare_faces(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, InputIterator2 end2) { std::list faces1; std::list faces2; for (InputIterator1 iter1 = begin1; iter1 != end1; ++iter1){ faces1.push_back(*(*iter1)); } for (InputIterator2 iter2 = begin2; iter2 != end2; ++iter2) faces2.push_back(*(*iter2)); // asserting both contianers have the same size of faces. CGAL_assertion(faces1.size() == faces2.size()); for (std::list::iterator face_iter = faces1.begin(); face_iter != faces1.end(); ++face_iter) { Equal_Face pred(*face_iter); std::list::iterator f = std::find_if(faces2.begin(), faces2.end(), pred); // asserting every face of faces1 is found in faces2. CGAL_assertion(f != faces2.end()); faces2.erase(f); } // asserting we have covered all faces from faces2. CGAL_assertion(faces2.empty()); } void check_intersection(const Bops& bop, const Polygon& polygon1, const Polygon& polygon2) { Polygon_list polygons; polygons.push_back(polygon1); polygons.push_back(polygon2); //Bops bop(pm1, pm2); Faces_container bops_faces; Halfedges_container bops_halfedges; Vertices_container bops_vertices; bop.intersection(bops_faces,bops_halfedges,bops_vertices); std::list faces; Arrangement arr; insert_polygons(arr,polygons); get_faces_with_covering(std::back_inserter(faces),arr,polygons.size()); cout<<"Face sizes:"< points; get_vertices_with_covering(polygons.begin(), polygons.end(), faces.begin(), faces.end(), std::back_inserter(points), arr, polygons.size()); std::set > set_points(points.begin(), points.end()); std::list bops_points; for (Vertices_container::iterator iter=bops_vertices.begin(); iter!=bops_vertices.end(); ++iter) bops_points.push_back((*iter)->point()); compare_vertices(set_points.begin(), set_points.end(), bops_points.begin(), bops_points.end()); std::cout << "Intersection: Vertices --- O.K "<< std::endl; //compare_halfedges(halfedges.begin(), halfedges.end(), // bops_halfedges.begin(), bops_halfedges.end()); } void check_union(const Bops &bop, const Polygon& polygon1, const Polygon& polygon2) { Polygon_list polygons; polygons.push_back(polygon1); polygons.push_back(polygon2); //Bops bop(pm1, pm2); Faces_container bops_faces; Halfedges_container bops_halfedges; Vertices_container bops_vertices; bop.Union(bops_faces,bops_halfedges,bops_vertices); std::list union_faces[2]; // faces[0] will contain the symmetric diff faces, and faces[1] will // contain the intersection faces. Arrangement arr; insert_polygons(arr,polygons); // For union we have to define all covers which are not 0. unsigned int i=1; for ( ; i <= polygons.size(); ++i) get_faces_with_covering(std::back_inserter(union_faces[i-1]),arr,i); std::list faces(union_faces[0].begin(), union_faces[0].end()); std::copy(union_faces[1].begin(), union_faces[1].end(), std::back_inserter(faces)); cout<<"Faces sizes:"< points; //std::set > union_points; for (i=1; i <= polygons.size(); ++i) { get_vertices_with_covering(polygons.begin(), polygons.end(), union_faces[i-1].begin(), union_faces[i-1].end(), std::back_inserter(points), arr, i); //for ( std::list::iterator p_iter } std::set > set_points(points.begin(), points.end()); std::list bops_points; for (Vertices_container::iterator iter=bops_vertices.begin(); iter!=bops_vertices.end(); ++iter) bops_points.push_back((*iter)->point()); compare_vertices(set_points.begin(), set_points.end(), bops_points.begin(), bops_points.end()); std::cout << "Union: Vertices --- O.K "<< std::endl; //compare_halfedges(halfedges.begin(), halfedges.end(), // bops_halfedges.begin(), bops_halfedges.end()); } void check_symmetric_difference(const Bops &bop, const Polygon& polygon1, const Polygon& polygon2) { Polygon_list polygons; polygons.push_back(polygon1); polygons.push_back(polygon2); //Bops bop(pm1, pm2); Faces_container bops_faces; Halfedges_container bops_halfedges; Vertices_container bops_vertices; bop.symmetric_difference(bops_faces,bops_halfedges,bops_vertices); std::list faces; Arrangement arr; insert_polygons(arr,polygons); // For symmetric difference we have to define all covers to be 1. get_faces_with_covering(std::back_inserter(faces), arr, 1); cout<<"Face sizes:"< points; get_vertices_with_covering(polygons.begin(), polygons.end(), faces.begin(), faces.end(), std::back_inserter(points), arr, 1); std::set > set_points(points.begin(), points.end()); std::list bops_points; for (Vertices_container::iterator iter=bops_vertices.begin(); iter!=bops_vertices.end(); ++iter) bops_points.push_back((*iter)->point()); compare_vertices(set_points.begin(), set_points.end(), bops_points.begin(), bops_points.end()); std::cout << "Symmetric Difference: Vertices --- O.K "<< std::endl; //compare_halfedges(halfedges.begin(), halfedges.end(), // bops_halfedges.begin(), bops_halfedges.end()); } //------------------------------- Scanning input functnions int get_next_int(std::ifstream& file) { int num = 0; //NT result(INT_MAX); std::string s; char c = 0; //file.set_ascii_mode(); while (file) { // try to convert next token to integer file >> c; if (c=='#') // comment { std::getline(file, s); } else // an integer number. { file.putback(c); file >> num; return num; } } return num; } void read_file_build_creator(std::ifstream & file, Pmwx & pm) { // read number of curves unsigned int num_curves = get_next_int(file); cout<<"num_curves="< curves; //Curve curr_curve; // read curves (test specific) int x1,y1,x2,y2; while (num_curves--) { //file >> curr_curve; file >>x1 >>y1 >> x2>> y2; Point p1(x1,y1), p2(x2,y2); curves.push_back(Curve(p1,p2)); } pm.insert(curves.begin(), curves.end()); } public: void start(char * filename) { std::ifstream file(filename); PmWalkPL pl_walk1, pl_walk2; Pmwx pm1(&pl_walk1), pm2(&pl_walk2); read_file_build_creator(file, pm1); read_file_build_creator(file, pm2); pm1.unbounded_face()->set_ignore_bop(false); pm2.unbounded_face()->set_ignore_bop(false); Polygon polygon1, polygon2; for (Vertex_iterator v_iter1=pm1.vertices_begin(); v_iter1!=pm1.vertices_end(); ++v_iter1) polygon1.push_back(v_iter1->point()); for (Vertex_iterator v_iter2=pm2.vertices_begin(); v_iter2!=pm2.vertices_end(); ++v_iter2) polygon2.push_back(v_iter2->point()); Faces_container bops_faces; Halfedges_container bops_halfedges; Vertices_container bops_vertices; //bop.intersection(bops_faces,bops_halfedges,bops_vertices); //cout<<"intersetion: bops_faces.size() "< 2) { std::cout << "usage: test data_file" << std::endl; std::exit(1); } test.start(argv[1]); return 0; } #endif // CGAL_ARR_TEST_LEDA_CONFLICT