// ====================================================================== // // Copyright (c) 1997 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------- // // release : $CGAL_Revision: CGAL-2.3-I-44 $ // release_date : $CGAL_Date: 2001/03/09 $ // // file : include/CGAL/Planar_map_2.h // package : pm (5.45) // maintainer : Eyal Flato // source : // revision : // revision_date : // author(s) : Iddo Hanniel // Eyal Flato // Oren Nechushtan // Eti Ezra // Shai Hirsch // // // coordinator : Tel-Aviv University (Dan Halperin ) // // Chapter : // ====================================================================== #ifndef CGAL_PLANAR_MAP_2_H #define CGAL_PLANAR_MAP_2_H #ifndef CGAL_PLANAR_MAP_MISC_H #include #endif #ifndef CGAL_PM_CHANGE_NOTIFICATION_H #include #endif #ifndef CGAL_TOPOLOGICAL_MAP_H #include #endif #ifndef CGAL_NO_PM_DEFAULT_POINT_LOCATION #ifndef CGAL_PM_DEFAULT_POINT_LOCATION_H #include #endif #ifndef CGAL_PM_WALK_ALONG_LINE_POINT_LOCATION_H #include #endif #ifndef CGAL_PM_NAIVE_POINT_LOCATION_H #include #endif //#else // CGAL_NO_PM_DEFAULT_POINT_LOCATION #ifndef CGAL_PM_POINT_LOCATION_BASE_H #include #endif #endif // CGAL_NO_PM_DEFAULT_POINT_LOCATION // for solving the dynamic cast in the copy constructor, // these lines will be removed after writing // copy construtor for point location. #ifndef CGAL_PM_WALK_ALONG_LINE_POINT_LOCATION_H #include #endif #ifndef CGAL_PM_NAIVE_POINT_LOCATION_H #include #endif // end. /*#ifndef CGAL_NO_PM_DEFAULT_POINT_LOCATION #ifndef CGAL_PM_DEFAULT_POINT_LOCATION_H #include #endif #else // CGAL_NO_PM_DEFAULT_POINT_LOCATION #ifndef CGAL_PM_POINT_LOCATION_BASE_H #include #endif*/ //#endif // CGAL_NO_PM_DEFAULT_POINT_LOCATION // default bounding box for finite curves #ifndef CGAL_PM_UNBOUNDING_BOX_H #include #endif // default bounding box for infinite curves #ifndef CGAL_PM_DYNAMIC_CLOSED_BOUNDING_BOX_H #include #endif #ifndef CGAL_IO_PM_FILE_SCANNER_H #include #endif // CGAL_IO_PM_FILE_SCANNER_H #include CGAL_BEGIN_NAMESPACE //////////////////////////////////////////////////////////////////////////// // PLANAR_MAP_2 template class Planar_map_2 : public Topological_map{ public: typedef Dcel_ Dcel; typedef Traits_ Traits; typedef Planar_map_2 Self; typedef Planar_map_traits_wrap Traits_wrap; typedef typename Traits::X_curve X_curve; typedef typename Traits::Point Point; typedef Point Point_2; typedef std::list X_curve_container; typedef Topological_map TPM; typedef typename TPM::Vertex_iterator Vertex_iterator; typedef typename TPM::Halfedge_iterator Halfedge_iterator; typedef typename TPM::Face_iterator Face_iterator; typedef typename TPM::Vertex_const_iterator Vertex_const_iterator; typedef typename TPM::Halfedge_const_iterator Halfedge_const_iterator; typedef typename TPM::Face_const_iterator Face_const_iterator; typedef typename TPM::Vertex_handle Vertex_handle; typedef typename TPM::Vertex_const_handle Vertex_const_handle; typedef typename TPM::Halfedge_handle Halfedge_handle; typedef typename TPM::Face_handle Face_handle; typedef typename TPM::Halfedge_const_handle Halfedge_const_handle; typedef typename TPM::Face_const_handle Face_const_handle; typedef typename TPM::Halfedge_around_vertex_circulator Halfedge_around_vertex_circulator; typedef typename TPM::Halfedge_around_vertex_const_circulator Halfedge_around_vertex_const_circulator; typedef typename TPM::Holes_iterator Holes_iterator; typedef typename TPM::Holes_const_iterator Holes_const_iterator; typedef typename TPM::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; typedef typename TPM::Ccb_halfedge_circulator Ccb_halfedge_circulator; typedef typename TPM::Size Size; typedef Pm_point_location_base Point_location_base; typedef Pm_bounding_box_base Bounding_box_base; typedef Pm_change_notification Change_notification; typedef enum{ VERTEX = 1, EDGE, FACE , UNBOUNDED_VERTEX, UNBOUNDED_EDGE, UNBOUNDED_FACE } Locate_type ; #ifndef CGAL_NO_PM_DEFAULT_POINT_LOCATION // constructor #1 - no parameters Planar_map_2 () { traits = new Traits_wrap(); use_delete_traits = true; pl = new Pm_default_point_location; use_delete_pl = true; pl->init(*this,*traits); bb=init_default_bounding_box((Traits*)traits); use_delete_bb=true; bb->init(*this,*traits); } #endif // constructor #2 - set only the PL Planar_map_2(Point_location_base *pl_ptr) { traits = new Traits_wrap(); use_delete_traits = true; pl = pl_ptr; use_delete_pl = false; pl->init(*this,*traits); bb = init_default_bounding_box((Traits*)traits); use_delete_bb = true; bb->init(*this,*traits); } // constructor #3 - copy traits, set pl and bb // set NULLs for defaults Planar_map_2(const Traits &tr_, Point_location_base *pl_ptr, Bounding_box_base *bb_ptr) { traits = new Traits_wrap(tr_); use_delete_traits = true; if (pl_ptr == NULL) { #ifndef CGAL_NO_PM_DEFAULT_POINT_LOCATION pl = new Pm_default_point_location; use_delete_pl = true; pl->init(*this,*traits); #else CGAL_assertion_msg( false, "No default point location is defined; you must supply one."); #endif } else { pl = pl_ptr; use_delete_pl = false; pl->init(*this,*traits); } if (bb_ptr == NULL) { bb=init_default_bounding_box((Traits*)traits); use_delete_bb=true; bb->init(*this,*traits); } else { bb = bb_ptr; use_delete_bb = false; bb->init(*this,*traits); } } // constructor #4 - set traits, pl and bb // set NULLs for defaults Planar_map_2(Traits_wrap *tr_ptr, Point_location_base *pl_ptr, Bounding_box_base *bb_ptr) { if (tr_ptr == NULL) { traits = new Traits_wrap(); use_delete_traits = true; } else { traits = tr_ptr; use_delete_traits = false; } if (pl_ptr == NULL) { #ifndef CGAL_NO_PM_DEFAULT_POINT_LOCATION pl = new Pm_default_point_location; use_delete_pl = true; pl->init(*this,*traits); #else CGAL_assertion_msg( false, "No default point location is defined; you must supply one."); #endif } else { pl = pl_ptr; use_delete_pl = false; pl->init(*this,*traits); } if (bb_ptr == NULL) { bb=init_default_bounding_box((Traits*)traits); use_delete_bb=true; bb->init(*this,*traits); } else { bb = bb_ptr; use_delete_bb = false; bb->init(*this,*traits); } } /////////////////////////////////////////////////////////////////////////////// // Copy constructor. /////////////////////////////////////////////////////////////////////////////// Planar_map_2(const Self& pm){ // doing the same as Planar_map_2(pm.get_traits(),pm.get_point_location(), // pm.get_point_bbox()); typedef Pm_naive_point_location > Pm_naive; typedef Pm_naive* Pm_naive_pointer; traits = new Traits_wrap(); use_delete_traits = true; if (Pm_naive_pointer tmp_pl = dynamic_cast(pm.pl) ){ //cout<<"Naive"<; } else if (Pm_walk_along_line_point_location* tmp_pl = dynamic_cast*>(pm.pl) ){ pl = new Pm_walk_along_line_point_location; //cout<<"Walk"<; #else CGAL_assertion_msg( false, "No default point location is defined; you must supply one."); #endif } use_delete_pl = true; pl->init(*this,*traits); bb=init_default_bounding_box((Traits*)traits); use_delete_bb=true; bb->init(*this,*traits); assign(pm); Halfedge_iterator h_iter; for (h_iter = halfedges_begin(); h_iter != halfedges_end(); h_iter++, h_iter++) pl->insert(h_iter, h_iter->curve()); for (Vertex_iterator v_iter = vertices_begin(); v_iter != vertices_end(); v_iter++) bb->insert(v_iter->point()); for (h_iter = halfedges_begin(); h_iter != halfedges_end(); h_iter++, h_iter++) bb->insert(h_iter->curve()); } ///////////////////////////////////////////////////////////////////////////// // Reading Planar map functions. //////////////////////////////////////////////////////////////////////////// bool read (std::istream &in) { clear(); Pm_file_scanner scanner(in); return scan_planar_map(scanner); } template bool read (std::istream &in, Scanner& scanner) { clear(); return scan_planar_map(scanner); } /* #ifndef CGAL_NO_PM_DEFAULT_POINT_LOCATION Planar_map_2 (const Traits& tr_=Traits()) : pl(new Pm_default_point_location),use_delete_pl(true) { traits = new Traits_wrap(tr_); use_delete_traits = true; pl->init(*this,*traits); bb=init_default_bounding_box(traits); use_delete_bb=true; bb->init(*this,*traits); } Planar_map_2( Bounding_box_base *bb_ptr, const Traits& tr_): pl(new Pm_default_point_location),bb(bb_ptr), use_delete_pl(true),use_delete_bb(false) { traits = new Traits_wrap(tr_); use_delete_traits = true; if (!bb) { bb=init_default_bounding_box(&tr_); use_delete_bb=true; } pl->init(*this,*traits); bb->init(*this,*traits); } Planar_map_2( Bounding_box_base *bb_ptr): pl(new Pm_default_point_location),bb(bb_ptr), traits(new Traits_wrap), use_delete_pl(true),use_delete_bb(false),use_delete_traits(true) { if (!bb) { bb=init_default_bounding_box((Traits*)0); use_delete_bb=true; } pl->init(*this,*traits); bb->init(*this,*traits); } #endif // CGAL_NO_PM_DEFAULT_POINT_LOCATION Planar_map_2 (Point_location_base *pl_ptr, Traits_wrap *tr_ptr) : pl(pl_ptr),use_delete_pl(false), traits(tr_ptr),use_delete_traits(false) { pl->init(*this,*traits); bb=init_default_bounding_box(traits); use_delete_bb=true; bb->init(*this,*traits); } Planar_map_2(Point_location_base *pl_ptr,const Traits& tr_) : pl(pl_ptr), use_delete_pl(false) { traits = new Traits_wrap(tr_); use_delete_traits = true; bb = init_default_bounding_box(traits); use_delete_bb = true; // initialize the bounding box. pl->init(*this,*traits); bb->init(*this,*traits); } Planar_map_2(Point_location_base *pl_ptr,Bounding_box_base *bb_ptr, const Traits& tr_) : pl(pl_ptr),bb(bb_ptr), use_delete_pl(false),use_delete_bb(false), { traits = new Traits_wrap(tr_); use_delete_traits = true; pl->init(*this,traits); bb->init(*this,traits); } Planar_map_2(Point_location_base *pl_ptr): pl(pl_ptr),bb(init_default_bounding_box((Traits*)0)), traits(new Traits_wrap), use_delete_pl(false),use_delete_bb(true),use_delete_traits(true) { if (!traits) { traits=new Traits_wrap; use_delete_traits=true; } // initialize the bounding box. pl->init(*this,*traits); bb->init(*this,*traits); } Planar_map_2( Point_location_base *pl_ptr,Bounding_box_base *bb_ptr): pl(pl_ptr),bb(bb_ptr), traits(new Traits_wrap), use_delete_pl(false), use_delete_bb(false), use_delete_traits(true) { pl->init(*this,*traits); bb->init(*this,*traits); } */ virtual ~Planar_map_2 () { if (use_delete_pl) delete pl; if (use_delete_bb) delete bb; if (use_delete_traits) delete traits; } // Inserts a new curve cv in the interior of the face f. // Returns the halfedge which is directed in the same way as the curve cv // (i.e., traits->curve_source(cv) == h.source()). Halfedge_handle insert_in_face_interior(const X_curve& cv, Face_handle f, Change_notification *en = NULL) { Halfedge_handle h = Topological_map::insert_in_face_interior(f); h->set_curve(cv); //should set the curve of the twin as well but for now h->twin()->set_curve(cv); //pl->insert(h); //maybe should be above //iddo - for arrangement pl->insert(h,cv); h->source()->set_point(traits->curve_source(cv)); h->target()->set_point(traits->curve_target(cv)); if (en != NULL) { en->add_edge(cv, h, true, false); en->add_hole(f, h); } return h; } Halfedge_handle insert_from_vertex(const X_curve& cv, Vertex_handle v1, bool source, Change_notification *en = NULL) { //find the previous of cv. Halfedge_around_vertex_circulator previous=v1->incident_halfedges(), after=previous, infinite_loop=previous; ++after; if (after!=previous) { while (!(traits->curve_is_between_cw(cv,previous->curve(), after->curve(),v1->point()))) { previous=after; ++after; if (previous==infinite_loop) // infinite loop indication { std::cerr << std::endl << "Planar_map_2::insert_from_vertex(" << "const X_curve& cv, Vertex_handle v1, " << "bool source) called with previously " << "inserted curve " << std::endl; return Halfedge_handle(); } } } Halfedge_handle h = Topological_map::insert_from_vertex(previous); h->set_curve(cv); h->twin()->set_curve(cv); //pl->insert(h); //maybe should be above //iddo - for arrangement pl->insert(h,cv); //h is now pointing from v1 if (source) h->target()->set_point(traits->curve_target(cv)); else h->target()->set_point(traits->curve_source(cv)); if (en != NULL) en->add_edge(cv, h,true, false); return h; } Halfedge_handle insert_at_vertices(const X_curve& cv, Vertex_handle v1, Vertex_handle v2, Change_notification *en = NULL) { Size num_before=number_of_faces(); Halfedge_around_vertex_circulator previous1=v1->incident_halfedges(), previous2=v2->incident_halfedges(), after=previous1, infinite_loop=previous1; ++after; if (after!=previous1) { while (!(traits->curve_is_between_cw(cv,previous1->curve(), after->curve(),v1->point()))) { previous1=after; ++after; if (previous1==infinite_loop) // infinite loop indication { std::cerr << std::endl << "Planar_map_2::insert_at_vertices(" << "const X_curve& cv, Vertex_const_handle v1, " << "Vertex_const_handle v2) called with previously " << "inserted curve " << std::endl; return Halfedge_handle(); } } } after=previous2; infinite_loop=previous2; ++after; if (after!=previous2) { while (!(traits->curve_is_between_cw(cv,previous2->curve(), after->curve(),v2->point()))) { previous2=after; ++after; if (previous2==infinite_loop) // infinite loop indication { std::cerr << std::endl << "Planar_map_2::insert_at_vertices(" << "const X_curve& cv, Vertex_const_handle v1," << "Vertex_const_handle v2) called with previously " << "inserted curve " << std::endl; return Halfedge_handle(); } } } bool prev1_before_prev2 = prev1_inside_hole(previous1,previous2,cv); Halfedge_handle h; if (prev1_before_prev2) h = Topological_map::insert_at_vertices(previous1,previous2); else h = Topological_map::insert_at_vertices(previous2,previous1); h->set_curve(cv); h->twin()->set_curve(cv); Size num_after=number_of_faces(); if (num_after-num_before) { //if additional face was added - move holes Face_handle nf = h->face(); //the new face will always be the one // pointed at by h Face_handle of = h->twin()->face(); //old face Holes_iterator it=of->holes_begin(); while (it!=of->holes_end()) { //check if the hole is inside new face // if ( point_is_in((*it)->target()->point(),nf) ) { //new for arrangement if ( point_is_in((*it)->target()->point(),h,cv) ) { Holes_iterator tmp=it; //deletion invalidates iterators so... ++it; //assumes only the erased iterator is invalidated (like stl //list) move_hole( tmp,of,nf); } else ++it; } } // v1 should be the source of h. if (!prev1_before_prev2) h=h->twin(); //pl->insert(h); //iddo - for arrangement pl->insert(h,cv); // Notifying change. if (en != NULL) { Face_handle orig_face = (! prev1_before_prev2) ? h->face() : h->twin()->face(); en->add_edge(cv, h, true, false); // After fixing the notifier we won't have to check that since // h->face() will be surely the new face. if (h->face() == orig_face) en->split_face(h->face(), h->twin()->face()); else en->split_face(h->twin()->face(), h->face()); // we surely know h->face() is the new face. //en->split_face(h->twin()->face(), h->face()); } return h; } bool is_empty() const {return halfedges_begin()==halfedges_end();} // Note that the return types are abstract base classes const Point_location_base* get_point_location() const {return pl;} const Bounding_box_base* get_bounding_box() const {return bb;} const Traits_wrap& get_traits() const { return *traits;} private: //a private implementation which defines if previous1 is on an outer ccb of //the new face (returns true) or on an inner ccb (returns false) bool prev1_inside_hole(Halfedge_const_handle previous1, Halfedge_const_handle previous2, const X_curve& cv) { /* Defining geometrically whether there is a new face. If there is, finds if previous1 is on the outside of the new face (send previous1,previous2) or on the inside of the new face (send previous2,previous1) The algorithm: 1. go over all the halfedges of the face which will hold previous1 (since the new face is not constructed yet, this is modeled by going from previous2->next to previous1 and then over the new curve) 2. find if the left-most-lower halfedge in the path (i.e, the one with the leftmost down target and is the lowest to the right among the incident edges of this vertex) is directed left (we are on the outside) or right (we are inside ) (if not on same ccb then it doesn't matter and return true) */ Ccb_halfedge_const_circulator left_edge(previous2); ++left_edge; Ccb_halfedge_const_circulator first(previous2),curr(left_edge), last(previous1); ++last; //we want the previous1 to be checked as well Point left = previous2->target()->point(); bool b; do { //source b=false; if (traits->point_is_left( curr->source()->point(),left)) b=true; else if (traits->point_is_same(curr->source()->point(),left)) { if (traits->curve_is_vertical(curr->curve()) && traits->point_is_lower(curr->target()->point(),left) ) b=true; else if (traits->curve_compare_at_x_right(curr->curve(), left_edge->curve(), left)==SMALLER ) b=true; } if (b) { left=curr->source()->point(); left_edge=curr; } //target b=false; if (traits->point_is_left( curr->target()->point(),left)) b=true; if (traits->point_is_same(curr->target()->point(),left)) { if (traits->curve_is_vertical(curr->curve()) && traits->point_is_lower(curr->source()->point(),left) ) b=true; else if (traits->curve_compare_at_x_right(curr->curve(), left_edge->curve(), left)==SMALLER ) b=true; //we want in the degenerate case to return the halfedge //pointing _at_ the left point else if ( (curr)==(left_edge->twin()) ) b=true; } if (b) { left=curr->target()->point(); left_edge=curr; } ++curr; } while ( (curr != first) && (curr != last) ); //test the new curve against left_edge if (traits->point_is_same(traits->curve_target(cv),left)|| traits->point_is_same(traits->curve_source(cv),left)) { if (traits->curve_is_vertical(cv)) { return (traits->point_is_lower(previous2->target()->point(), previous1->target()->point())); } else if (traits->curve_compare_at_x_right(cv,left_edge->curve(), left)==SMALLER ) { return (traits->point_is_left(previous1->target()->point(), previous2->target()->point())); } } //check if left_edge is from left to right if (traits->curve_is_vertical(left_edge->curve())) { if (traits->point_is_lower(left_edge->source()->point(), left_edge->target()->point())) return false; else return true; } return (traits->point_is_left(left_edge->source()->point(), left_edge->target()->point())); } public: Halfedge_handle insert(const X_curve& cv, Change_notification *en = NULL) { CGAL_assertion(bb); bb->insert(cv); if (traits->curve_is_degenerate(cv)) { std::cerr << "\nPlanar_map_2::insert(const X_curve& cv) " << "called with a null length curve " << cv << std::flush; return Halfedge_handle(); } Locate_type lt1,lt2; Point p1=traits->curve_source(cv); Point p2=traits->curve_target(cv); // The point location may not change the bounding box. Halfedge_handle h1=((const Point_location_base*)pl)->locate(p1,lt1); Halfedge_handle h2=((const Point_location_base*)pl)->locate(p2,lt2); if (lt1==EDGE || lt1==UNBOUNDED_EDGE) // the curve intersects the bounding box. { Halfedge_handle h=h1,h2; bb->split_boundary_edge(h,h1,h2,p1); // make sure the intersection point is in the map, // i.e. split the halfedge that contains its. lt1=VERTEX; } if (lt2==EDGE || lt2==UNBOUNDED_EDGE) { Halfedge_handle h1,h=h2; bb->split_boundary_edge(h,h1,h2,p2); // make sure the intersection point is in the map, // i.e. split the halfedge that contains its. lt1=VERTEX; } if (lt1==VERTEX && lt2==VERTEX) return insert_at_vertices(cv,h1->target(),h2->target(), en); if (lt1==VERTEX && lt2!=VERTEX) return insert_from_vertex(cv,h1->target(),true, en); if (lt1!=VERTEX && lt2==VERTEX) return insert_from_vertex(cv,h2->target(),false, en)->twin(); if (lt1==UNBOUNDED_FACE) return insert_in_face_interior(cv,unbounded_face(), en); if (lt1==FACE) return insert_in_face_interior(cv,h1->face(), en); CGAL_postcondition(lt1==VERTEX||lt1==UNBOUNDED_FACE||lt1==FACE); return Halfedge_handle(); } template Halfedge_iterator insert(const X_curve_iterator& begin, const X_curve_iterator& end, Change_notification *en = NULL) { X_curve_iterator it=begin; Halfedge_iterator out; if (it!=end) { out=insert(*it, en); it++; } while (it!=end) { insert(*it, en); it++; } return out; } Halfedge_handle split_edge(Halfedge_handle e, const X_curve & c1, const X_curve & c2, Change_notification * en = NULL) { CGAL_precondition(traits->point_is_same(traits->curve_source(c2), traits->curve_target(c1))); CGAL_precondition( traits->point_is_same( traits->curve_source(c1), e->source()->point()) && traits->point_is_same( traits->curve_target(c2), e->target()->point()) || traits->point_is_same( traits->curve_source(c1), e->target()->point()) && traits->point_is_same( traits->curve_target(c2), e->source()->point()) ); X_curve cv(e->curve()); Halfedge_handle h = Topological_map::split_edge(e); if (traits->point_is_same(traits->curve_source(c1),h->source()->point())) { h->set_curve(c1); h->twin()->set_curve(c1); h->next_halfedge()->set_curve(c2); h->next_halfedge()->twin()->set_curve(c2); h->target()->set_point(traits->curve_target(c1)); pl->split_edge(cv,h,h->next_halfedge(),c1,c2); if (en != NULL) en->split_edge(h, h->next_halfedge(), c1, c2); } else { h->set_curve(c2); h->twin()->set_curve(c2); h->next_halfedge()->set_curve(c1); h->next_halfedge()->twin()->set_curve(c1); h->target()->set_point(traits->curve_target(c1)); pl->split_edge(cv,h,h->next_halfedge(),c2,c1); if (en != NULL) en->split_edge(h, h->next_halfedge(), c2, c1); } //if (en != NULL) // en->split_edge(h, h->next_halfedge(), c1, c2); return h; } Halfedge_handle merge_edge(Halfedge_handle e1, Halfedge_handle e2, const X_curve& cv, Change_notification * en = NULL) { CGAL_precondition( (traits->point_is_same(traits->curve_source(cv), e1->source()->point() )&& traits->point_is_same(traits->curve_target(cv), e2->target()->point())) || (traits->point_is_same(traits->curve_target(cv), e1->source()->point() )&& traits->point_is_same(traits->curve_source(cv), e2->target()->point())) ); // problematic: since we assume e1 will be the new merged halfedge // after merging. en->merge(e1,e2,cv); X_curve c1(e1->curve()), c2(e2->curve()); Halfedge_handle h = Topological_map::merge_edge(e1,e2); h->set_curve(cv); h->twin()->set_curve(cv); //pl->merge_edge(c1,c2,h); //iddo - for arrangement pl->merge_edge(c1,c2,h,cv); // problematic: e2 does not exist anymore //if (en != NULL) // en->merge_edge(h, e1, e2, cv); return h; } Face_handle remove_edge(Halfedge_handle e) { // en->remove_edge(e); pl->remove_edge(e); //if a new hole can be created define geometrically the //halfedge (e or e->twin) that points at the new hole. //if the leftmost point in the path e...e->twin //is left of the leftmost point in the path e->twin ... e //then e->twin points at the hole created. if (e->face() == e->twin()->face() ) { Ccb_halfedge_circulator ccb_e=e->ccb() ; Ccb_halfedge_circulator ccb_t=e->twin()->ccb(); Point e_left=e->target()->point(); Point t_left=ccb_t->target()->point(); //find the leftmost point in the path from e to its twin Ccb_halfedge_circulator aux=ccb_e; do { if (traits->compare_x(aux->target()->point(),e_left)==SMALLER) { e_left=aux->target()->point(); } } while (++aux!=ccb_t); //find the leftmost point in the path from the twin to e aux=ccb_t; do { if (traits->compare_x(aux->target()->point(),t_left)==SMALLER) { t_left=aux->target()->point(); } } while (++aux!=ccb_e); //compare the two left points if (traits->compare_x(t_left,e_left) == SMALLER) //e points at hole return Topological_map::remove_edge(e); else return Topological_map::remove_edge(e->twin()); } else { return Topological_map::remove_edge(e); } } Halfedge_handle vertical_ray_shoot(const Point& p, Locate_type <, bool up) { CGAL_precondition(pl); return pl->vertical_ray_shoot(p,lt,up); } Halfedge_const_handle vertical_ray_shoot(const Point& p, Locate_type <, bool up) const { CGAL_precondition(pl); return ((const Point_location_base*)pl)->vertical_ray_shoot(p,lt,up); // The type cast to const is there to ensure that the planar map // is not changed. } Halfedge_handle locate(const Point& p, Locate_type <) { CGAL_precondition(pl); return pl->locate(p,lt); } Halfedge_const_handle locate(const Point& p, Locate_type <) const { CGAL_precondition(pl); return ((const Point_location_base*)pl)->locate(p,lt); // The type cast to const is there to ensure that the planar map // is not changed. } protected: //private implementation //returns true if the point is inside (in the strict sense) of nf //algorithm: count the intersections of a vertical ray shoot - are they odd ? //assumes outer ccb exists //CHANGE - for this to work in the arrangement, it should not pass over //the curve just inserted (i.e the halfedge) /* bool point_is_in(const Point& p, Face_const_handle nf) const { int count = 0; Ccb_halfedge_const_circulator circ = nf->outer_ccb(); do { ++circ; } while ((traits->curve_is_vertical(circ->curve()))&& circ!=nf->outer_ccb()); if (circ==nf->outer_ccb() && traits->curve_is_vertical(circ->curve()) ) return false; //if the whole ccb is vertical then the point is out. //else advance to a non vertical curve Ccb_halfedge_const_circulator last = circ; do { if (traits->point_is_same(circ->target()->point(), p)) //point is on outer ccb return false; if (!traits->curve_is_vertical(circ->curve())) { if ( (traits->curve_get_point_status(circ->curve(),p) == Traits::UNDER_CURVE) && !(traits->point_is_same_x(circ->source()->point(),p)) ) { //point is under curve in the range (source,target] if (traits->point_is_same_x(circ->target()->point(),p)) { //p is exactly under a vertex of the ccb - if next is not on the //same side of the vertical line from p as circ is, //we count one more intersection Ccb_halfedge_const_circulator next=circ; ++next; if (traits->curve_is_vertical(next->curve())) { //advance to non-vertical edge while (traits->curve_is_vertical(next->curve())) { ++next; } } if ( (traits->point_is_right(circ->source()->point(),p)&& traits->point_is_left(next->target()->point(),p)) || (traits->point_is_left(circ->source()->point(),p)&& traits->point_is_right(next->target()->point(),p)) ) { ++count; } } else { ++count; } } } } while (++circ!=last); return (count%2 != 0); //if count is odd return true } */ // Determines if an input point is within the face incident // to an input halfedge. // // p - input point // ne - handle of input halfedge // nvc - curve of input halfedge // // return value - true iff the above condition holds // // Implementation: // Conceptually, we shoot a ray from p vertically upwards and count // the number of pm-halfedges of the boundary of the face that intersect it. // If this number is odd the point is inside the face. In practice, we // we use a check whether a curve is above or below a point. // bool point_is_in(const Point & p, Halfedge_const_handle ne, const X_curve & ncv) const { // count stores the number of curves that intersect the upward vertical // ray shot from p (except for a degenerate case which is explained in // the code) int count = 0; // 1. Find the first halfedge, whose curve is non-vertical, along // the ccb that includes input halfedge ne. Ccb_halfedge_const_circulator circ = ne; do { ++circ; } while ( circ != ne && traits->curve_is_vertical(circ->curve()) ); // If the whole ccb is vertical then there is no face, so point p // cannot be in it if ( circ == ne && traits->curve_is_vertical(ncv) ) return false; // 2. Go over all curves of the ccb and count those which are above p. Ccb_halfedge_const_circulator last = circ; do { // Put curve of current halfedge in circv. X_curve circv; // If not on the new halfedge circ definitely has a curve if (circ != ne) { circv=circ->curve(); } // o/w, circ might not have a curve yet (e.g in arrangement) // so we take the input curve. else { circv=ncv; } // If query point is vertex point on the outer ccb if (traits->point_is_same(circ->target()->point(), p)) return false; // If current curve is not vertical if ( ! traits->curve_is_vertical(circv)) { // If point is under current curve in the range (source,target] of it if ( (traits->curve_get_point_status(circv,p) == Traits::UNDER_CURVE) && ! (traits->point_is_same_x(circ->source()->point(), p)) ) { // If p is exactly under a vertex of the ccb if (traits->point_is_same_x(circ->target()->point(), p)) { // Put curve of next halfedge that is not vertical in nextcv Ccb_halfedge_const_circulator next = circ; ++next; X_curve nextcv; if (next != ne) { nextcv = next->curve(); } else { nextcv = ncv; } if (traits->curve_is_vertical(nextcv)) { //advance to non-vertical edge while (traits->curve_is_vertical(nextcv)) { if (next!=ne) { nextcv=next->curve(); } else { nextcv=ncv; } ++next; } } // If nextcv is on the same side of the vertical line // from p as circv is if ( (traits->point_is_right(circ->source()->point(),p)&& traits->point_is_left(next->target()->point(),p)) || (traits->point_is_left(circ->source()->point(),p)&& traits->point_is_right(next->target()->point(),p)) ) { // then we raise the count ++count; } } else { // o/w, point p is under the interior of the current curve // so we raise the count ++count; } } } // If current curve is not vertical } while (++circ != last); return (count%2 != 0); //if count is odd return true } ///////////////////////////////////////////////////////// // Assignment functions // Those are temporary functions and it should not be used public: void assign(const Self &pm) { TPM::assign(pm); // traits->assign(pm->traits); // bb->assign(pm->bb); // pl->assign(pm->pl); } /*Self& operator=(const Self& pm) { if (this != &pm) { X_curve_container l; pm.x_curve_container(l); clear(); insert(l.begin(), l.end()); } return *this; } */ Self& operator=(const Self& pm) { if (this != &pm) { clear(); assign(pm); Halfedge_iterator h_iter; for (h_iter = halfedges_begin(); h_iter != halfedges_end(); h_iter++, h_iter++) pl->insert(h_iter, h_iter->curve()); for (Vertex_iterator v_iter = vertices_begin(); v_iter != vertices_end(); v_iter++) bb->insert(v_iter->point()); for (h_iter = halfedges_begin(); h_iter != halfedges_end(); h_iter++, h_iter++) bb->insert(h_iter->curve()); } return *this; } // used in implementation of operator=( void clear() { pl->clear(); TPM::clear(); /* Halfedge_iterator it=halfedges_begin(),prev=it,it_e=halfedges_end(); while (it!=it_e) {++it;++it;remove_edge(prev);prev=it;} */ bb->clear(); } protected: // used in implementation of operator=( void x_curve_container(X_curve_container &l) const { Halfedge_const_iterator it=halfedges_begin(),it_e=halfedges_end(); while (it!=it_e) { l.push_back(it->curve()); ++it;++it; } } // ///////////////////////////////////////////////////////// protected: // default initializer for the bounding box. #include #ifdef CGAL_PM_DEBUG // for private debugging use public: void debug() { if (pl) (pl->debug()); } #endif private: /////////////////////////////////////////////////////////////////////////// // Scanning Arrangement. ///////////////////////////////////////////////////////////////////////// template bool scan_planar_map (Scanner& scanner){ if (!build_dcel(scanner)) return false; return true; } template bool build_dcel (Scanner& scanner) { typedef typename Dcel::Vertex D_vertex; typedef typename Dcel::Halfedge D_halfedge; typedef typename Dcel::Face D_face; typedef typename Dcel::Vertex_iterator D_vetrex_iterator; typedef typename Dcel::Vertex_const_iterator D_vetrex_const_iterator; typedef typename Dcel::Halfedge_iterator D_halfedge_iterator; typedef typename Dcel::Halfedge_const_iterator D_halfedge_const_iterator; typedef typename Dcel::Face_iterator D_face_iterator; typedef typename Dcel::Face_const_iterator D_face_const_iterator; // keeping a vector of halfedges (to access them easily by their indices). std::vector halfedges_vec; std::vector vertices_vec; if ( ! scanner.in()) return 0; scanner.scan_pm_vhf_sizes(); if ( ! scanner.in()){ std::cerr << "can't read vhf values"<set_point(p); // for debug. //std::cout<<"Reading vertex no " <point()<insert(nv->point()); //scanner.skip_to_next_vertex(); //if ( ! scanner.in()){ // std::cerr << "can't skip to next vertex"<set_curve(cv); /*scanner.scan_halfedge_attributes (nh->opposite()); if ( ! scanner.in()){ std::cerr << "can't read halfedge attributes"<opposite()); if ( ! scanner.in()){ std::cerr << "can't read halfedge"<opposite()->set_curve(cv); nv1 = vertices_vec[index1]; ((D_vertex*) nv1)->set_halfedge(nh); nh->set_vertex((D_vertex*) nv1); //for debug //std::cout<<((D_vertex*) nv1)->point()<set_halfedge(nh->opposite()); nh->opposite()->set_vertex((D_vertex*) nv2); //for debug //std::cout<<((D_vertex*) nv2)->point()<insert(D_halfedge_iterator(nh->opposite()), cv); bb->insert(cv); halfedges_vec.push_back(nh); halfedges_vec.push_back(nh->opposite()); //scanner.skip_to_next_halfedge(); //if ( ! scanner.in()){ // std::cerr << "can't skip to next halfedge"< 0) // else - allocate the bounded face. nf = d.new_face(); scanner.scan_face(nf); if ( ! scanner.in()){ std::cerr << "can't read face"< 0){ // not an unbounded face. Scanning the outer ccb. scanner.scan_face_number(num_halfedges_on_outer_ccb, i); if ( ! scanner.in()){ std::cerr << "can't read face number"< 0) { std::size_t index, prev_index, first_index; for (unsigned int j = 0; j < num_halfedges_on_outer_ccb; j++) { scanner.scan_index(index); if ( ! scanner.in()){ std::cerr << "can't read halfedge's index on face"<vertex()->point()< 0) { D_halfedge* prev_nh = halfedges_vec[prev_index]; prev_nh->set_next(nh); } else { nf->set_halfedge(nh); first_index = index; } nh->set_face(nf); prev_index = index; } // making the last halfedge point to the first one (cyclic order). D_halfedge* nh = halfedges_vec[first_index]; D_halfedge* prev_nh = halfedges_vec[prev_index]; prev_nh->set_next(nh); } scanner.scan_face_number(num_of_holes, i); if ( ! scanner.in()){ std::cerr << "can't read number holes in face"<vertex()->point()< 0) { D_halfedge* prev_nh = halfedges_vec[prev_index]; prev_nh->set_next(nh); } else { nf->add_hole(nh); first_index = index; } nh->set_face(nf); prev_index = index; } // making the last halfedge point to the first one (cyclic order). D_halfedge* nh = halfedges_vec[first_index]; D_halfedge* prev_nh = halfedges_vec[prev_index]; prev_nh->set_next(nh); } scanner.skip_to_next_face(i); if ( ! scanner.in()){ std::cerr << "can't skip to next face"<