BWAPI
|
00001 // Copyright (c) 1997-2000 Max-Planck-Institute Saarbruecken (Germany). 00002 // All rights reserved. 00003 // 00004 // This file is part of CGAL (www.cgal.org); you may redistribute it under 00005 // the terms of the Q Public License version 1.0. 00006 // See the file LICENSE.QPL distributed with CGAL. 00007 // 00008 // Licensees holding a valid commercial license may use this file in 00009 // accordance with the commercial license agreement provided with the software. 00010 // 00011 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00012 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00013 // 00014 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Nef_2/include/CGAL/Nef_2/PM_checker.h $ 00015 // $Id: PM_checker.h 40851 2007-11-09 15:27:44Z ameyer $ 00016 // 00017 // 00018 // Author(s) : Michael Seel <seel@mpi-sb.mpg.de> 00019 00020 #ifndef CGAL_PM_CHECKER_H 00021 #define CGAL_PM_CHECKER_H 00022 00023 #include <CGAL/basic.h> 00024 #include <CGAL/Unique_hash_map.h> 00025 #include <CGAL/Nef_2/PM_const_decorator.h> 00026 00027 CGAL_BEGIN_NAMESPACE 00028 00029 /*{\Moptions outfile=PM_checker.man }*/ 00030 /*{\Manpage {PM_checker}{PMCDEC,GEOM}{Plane map checking}{}}*/ 00031 00032 /*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a 00033 decorator to check the structure of a plane map. It is generic with 00034 respect to two template concepts. |PMCDEC| has to be a decorator 00035 model of our |PM_const_decorator| concept. |GEOM| has to be a model of 00036 our geometry kernel concept.}*/ 00037 00038 /*{\Mgeneralization PM_const_decorator}*/ 00039 00040 template <typename PMCDEC, typename GEOM> 00041 class PM_checker : public PMCDEC 00042 { typedef PMCDEC Base; 00043 const GEOM& K; 00044 public: 00045 /*{\Mtypes 3}*/ 00046 typedef PMCDEC PM_const_decorator; 00047 /*{\Mtypemember equals |PMCDEC|.}*/ 00048 typedef typename PMCDEC::Plane_map Plane_map; 00049 /*{\Mtypemember equals |PMCDEC::Plane_map|, the underlying plane map type.}*/ 00050 typedef GEOM Geometry; 00051 /*{\Mtypemember equals |GEOM|. Add link to GEOM concept.\\ 00052 \precond |Geometry::Point_2| equals |Plane_map::Point|. }*/ 00053 00054 typedef typename GEOM::Point_2 Point; 00055 typedef typename GEOM::Direction_2 Direction; 00056 00057 typedef typename Base::Vertex_const_handle Vertex_const_handle; 00058 typedef typename Base::Halfedge_const_handle Halfedge_const_handle; 00059 typedef typename Base::Vertex_const_iterator Vertex_const_iterator; 00060 typedef typename Base::Halfedge_const_iterator Halfedge_const_iterator; 00061 typedef typename Base::Halfedge_around_vertex_const_circulator Halfedge_around_vertex_const_circulator; 00062 typedef typename Base::Halfedge_around_face_const_circulator Halfedge_around_face_const_circulator; 00063 00064 00065 using Base::clear; 00066 using Base::vertices_begin; 00067 using Base::vertices_end; 00068 using Base::halfedges_begin; 00069 using Base::halfedges_end; 00070 using Base::faces_begin; 00071 using Base::faces_end; 00072 using Base::number_of_vertices; 00073 using Base::number_of_halfedges; 00074 using Base::number_of_edges; 00075 using Base::number_of_faces; 00076 using Base::number_of_connected_components; 00077 using Base::check_integrity_and_topological_planarity; 00078 00079 /*{\Mtext Iterators, handles, and circulators are inherited from 00080 |PM_const_decorator|.}*/ 00081 00082 /*{\Mcreation 3}*/ 00083 PM_checker(Plane_map& P, const Geometry& k = Geometry()) : 00084 Base(P), K(k) {} 00085 /*{\Mcreate constructs a plane map checker working on |P| with 00086 geometric predicates used from |k|.}*/ 00087 00088 PM_checker(const Base& D, const Geometry& k = Geometry()) : 00089 Base(D), K(k) {} 00090 00091 00092 /*{\Moperations 2 }*/ 00093 Direction direction(Halfedge_const_handle e) const 00094 { return K.construct_direction( 00095 point(source(e)),point(target(e))); } 00096 00097 bool is_forward(Halfedge_const_handle e) const 00098 { return K.compare_xy(point(source(e)),point(target(e)))<0; } 00099 00100 void check_order_preserving_embedding(Vertex_const_handle v) const; 00101 /*{\Mop checks if the embedding of the targets of the edges in 00102 the adjacency list |A(v)| is counter-clockwise order-preserving with 00103 respect to the order of the edges in |A(v)|.}*/ 00104 00105 void check_order_preserving_embedding() const; 00106 /*{\Mop checks if the embedding of all vertices of |P| is 00107 counter-clockwise order-preserving with respect to the adjacency 00108 list ordering of all vertices.}*/ 00109 00110 void check_forward_prefix_condition(Vertex_const_handle v) const; 00111 /*{\Mop checks the forward-prefix property of the adjacency list of |v|.}*/ 00112 00113 Halfedge_const_iterator 00114 check_boundary_is_clockwise_weakly_polygon() const; 00115 /*{\Mop checks if the outer face cycle of |P| is a clockwise weakly polygon 00116 and returns a halfedge on the boundary. \precond |P| is a connected graph. 00117 }*/ 00118 00119 void check_is_triangulation() const; 00120 /*{\Mop checks if |P| is a triangulation.}*/ 00121 00122 }; // PM_checker<PMCDEC,GEOM> 00123 00124 00125 template <typename PMCDEC, typename GEOM> 00126 void PM_checker<PMCDEC,GEOM>:: 00127 check_order_preserving_embedding(Vertex_const_handle v) const 00128 { 00129 if ( is_isolated(v) ) return; 00130 std::ostringstream error_status; 00131 CGAL::set_pretty_mode ( error_status ); 00132 Halfedge_const_handle ef = first_out_edge(v) ,e=ef,en,enn; 00133 error_status << "check_order_preserving_embedding\n"; 00134 error_status << "vertex " << PV(v) << std::endl; 00135 error_status << "ef " << PE(ef) << std::endl; 00136 while ( true ) { 00137 en = cyclic_adj_succ(e); 00138 enn = cyclic_adj_succ(en); 00139 if (en == ef) break; 00140 error_status << " -> " << point(target(e)) 00141 << " " << point(target(en)) 00142 << " " << point(target(enn)) << std::endl; 00143 bool ccw1 = K.strictly_ordered_ccw(direction(e),direction(en), 00144 direction(enn)); 00145 bool ccw2 = K.strictly_ordered_ccw(direction(e),direction(en), 00146 direction(ef)); 00147 if ( !(ccw1 && ccw2) ) { 00148 error_status << "ccw order violate!" << std::endl << '\0'; 00149 CGAL_error_msg(error_status.str().c_str()); 00150 } 00151 e = en; 00152 } 00153 } 00154 00155 template <typename PMCDEC, typename GEOM> 00156 void PM_checker<PMCDEC,GEOM>:: 00157 check_forward_prefix_condition(Vertex_const_handle v) const 00158 { Halfedge_const_handle ef = first_out_edge(v); 00159 if ( ef == Halfedge_const_handle() ) return; 00160 Halfedge_const_handle el = cyclic_adj_pred(ef); 00161 bool is_left_turn = K.left_turn(point(v), 00162 point(target(ef)), 00163 point(target(el))); 00164 bool el_forward = is_forward(el); 00165 bool ef_forward = is_forward(ef); 00166 bool ef_el_eq = (ef==el); 00167 std::ostringstream error_status; 00168 error_status << "check_forward_prefix_condition: "; 00169 error_status << PV(v) << "\n"; 00170 error_status << PE(ef) << "\n" << PE(el) << "\n"; 00171 error_status << " ef == el = " << ef_el_eq; 00172 error_status << " ef_forward = " << ef_forward; 00173 error_status << " el_forward = " << el_forward; 00174 error_status << " is_left_turn = " << is_left_turn; 00175 CGAL_assertion_msg( (ef == el || 00176 ef_forward && !el_forward || 00177 ef_forward && el_forward && is_left_turn || 00178 !ef_forward && !el_forward && is_left_turn) , 00179 error_status.str().c_str()); 00180 } 00181 00182 /* We check the geometric integrity of the structure. We check 00183 + that all adjacent nodes are differently embedded 00184 + that all node lists are correctly embedded counterclockwise 00185 with winding number one. 00186 + that the convex hull of the structure has winding number one. 00187 */ 00188 00189 template <typename PMCDEC, typename GEOM> 00190 void PM_checker<PMCDEC,GEOM>:: 00191 check_order_preserving_embedding() const 00192 { 00193 Vertex_const_iterator vit; 00194 for (vit = this->vertices_begin(); vit != this->vertices_end(); ++vit) { 00195 check_order_preserving_embedding(vit); 00196 check_forward_prefix_condition(vit); 00197 } 00198 } 00199 00200 00201 template <typename PMCDEC, typename GEOM> 00202 typename PM_checker<PMCDEC,GEOM>::Halfedge_const_iterator 00203 PM_checker<PMCDEC,GEOM>:: 00204 check_boundary_is_clockwise_weakly_polygon() const 00205 { 00206 Vertex_const_iterator vit, v_min; 00207 for (vit = v_min = this->vertices_begin() ; vit != this->vertices_end(); ++vit) 00208 if ( K.compare_xy(point(vit), point(v_min))<0 ) v_min = vit; 00209 CGAL_assertion_msg(!is_isolated(v_min),"Minimal vertex not connected."); 00210 Point p_min = point(v_min); 00211 // determine boundary edge incident to v_min: 00212 Halfedge_const_handle e_boundary_at_v_min = first_out_edge(v_min); 00213 // all out edges are forward oriented due to minimality 00214 Halfedge_around_vertex_const_circulator 00215 hvit(e_boundary_at_v_min), hend(hvit); 00216 do { 00217 --hvit; 00218 Point p1 = point(target(e_boundary_at_v_min)); 00219 Point p2 = point(target(hvit)); 00220 if ( K.orientation(p_min,p1,p2) > 0 ) { // left_turn 00221 e_boundary_at_v_min = hvit; 00222 break; 00223 } 00224 } while (hvit != hend); 00225 // now e_boundary_at_v_min is highest starting edge in bundle!! 00226 00227 int winding_around_globally=0; 00228 Halfedge_around_face_const_circulator 00229 hfit(e_boundary_at_v_min),hstart(hfit); 00230 Halfedge_const_handle e_prev = next(e_boundary_at_v_min); 00231 /* we run counterclockwise around the outer face cycle and allow only 00232 position where the direction vector of an edge gets smaller again */ 00233 Direction d_prev = direction(e_prev); 00234 CGAL_For_all_backwards(hstart,hfit) { 00235 Direction d_curr = direction(hfit); 00236 if ( d_curr < d_prev ) ++winding_around_globally; 00237 d_prev = d_curr; 00238 } 00239 CGAL_assertion(winding_around_globally == 1); 00240 return e_boundary_at_v_min; 00241 } 00242 00243 template <typename PMCDEC, typename GEOM> 00244 void PM_checker<PMCDEC,GEOM>:: 00245 check_is_triangulation() const 00246 { 00247 Halfedge_const_iterator eb; 00248 CGAL_assertion(this->number_of_connected_components() == 1); 00249 CGAL_assertion_msg(this->number_of_edges()!=this->number_of_vertices()-1, 00250 " checker checks only full dimensional complexes."); 00251 this->check_integrity_and_topological_planarity(false); 00252 check_order_preserving_embedding(); 00253 eb = check_boundary_is_clockwise_weakly_polygon(); 00254 00255 CGAL::Unique_hash_map< Halfedge_const_iterator, bool> on_boundary(false); 00256 Halfedge_around_face_const_circulator hit(eb), hend(hit); 00257 std::ostringstream error_status; 00258 CGAL::set_pretty_mode ( error_status ); 00259 error_status << "check_is_triangulation\n"; 00260 error_status << "on boundary:\n"; 00261 CGAL_For_all(hit,hend) { 00262 error_status << " " << PE(hit) << std::endl; 00263 on_boundary[hit]=true; 00264 } 00265 Halfedge_const_iterator eit; 00266 for( eit = this->halfedges_begin(); eit != this->halfedges_end(); ++eit) { 00267 if (on_boundary[eit]) continue; 00268 hit = hend = eit; 00269 int edges_in_face_cycle=0; 00270 CGAL_For_all(hit,hend) { 00271 error_status << PE(hit); 00272 ++edges_in_face_cycle; 00273 } 00274 CGAL_assertion_msg(edges_in_face_cycle==3,error_status.str().c_str()); 00275 CGAL_assertion_msg( 00276 K.left_turn(point(source(hit)),point(target(hit)), 00277 point(target(next(hit)))), error_status.str().c_str()); 00278 } 00279 } 00280 00281 00282 00283 CGAL_END_NAMESPACE 00284 00285 00286 #endif // CGAL_PM_CHECKER_H 00287