BWAPI
|
00001 // Copyright (c) 2002 Utrecht University (The Netherlands). 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/Spatial_searching/include/CGAL/Point_container.h $ 00015 // $Id: Point_container.h 36901 2007-03-07 19:34:29Z fcacciola $ 00016 // 00017 // 00018 // Author(s) : Hans Tangelder (<hanst@cs.uu.nl>) 00019 00020 00021 // custom point container 00022 #ifndef CGAL_POINT_CONTAINER_H 00023 #define CGAL_POINT_CONTAINER_H 00024 00025 #include <list> 00026 #include <vector> 00027 #include <functional> 00028 #include <algorithm> 00029 #include <CGAL/Kd_tree_rectangle.h> 00030 00031 #include <boost/optional.hpp> 00032 00033 namespace CGAL { 00034 00035 template <class Traits> 00036 class Point_container { 00037 00038 private: 00039 typedef typename Traits::Point_d Point_d; 00040 typedef std::vector<Point_d*> Point_vector; 00041 00042 public: 00043 typedef typename Traits::FT FT; 00044 00045 typedef typename Point_vector::iterator iterator; 00046 00047 private: 00048 00049 // the iterator range of the Point_container 00050 boost::optional<iterator> m_b ; 00051 boost::optional<iterator> m_e ; 00052 00053 int built_coord; // a coordinate for which the pointer list is built 00054 Kd_tree_rectangle<Traits> bbox; // bounding box, i.e. rectangle of node 00055 Kd_tree_rectangle<Traits> tbox; // tight bounding box, 00056 // i.e. minimal enclosing bounding 00057 // box of points 00058 00059 public: 00060 00061 inline const Kd_tree_rectangle<Traits>& 00062 bounding_box() const 00063 { 00064 return bbox; 00065 } 00066 00067 inline const Kd_tree_rectangle<Traits>& 00068 tight_bounding_box() const 00069 { 00070 return tbox; 00071 } 00072 00073 inline int 00074 dimension() const 00075 { 00076 return bbox.dimension(); 00077 } 00078 00079 inline int 00080 built_coordinate() const 00081 { 00082 return built_coord; 00083 } 00084 00085 // coordinate of the maximal span 00086 inline int 00087 max_span_coord() const 00088 { 00089 return bbox.max_span_coord(); 00090 } 00091 00092 // coordinate of the maximal tight span 00093 inline int 00094 max_tight_span_coord() const 00095 { 00096 return tbox.max_span_coord(); 00097 } 00098 00099 inline FT 00100 max_span_lower() const 00101 { 00102 return bbox.min_coord(max_span_coord()); 00103 } 00104 00105 inline FT 00106 max_tight_span_lower() const 00107 { 00108 return tbox.min_coord(max_tight_span_coord()); 00109 } 00110 00111 inline FT 00112 max_span_upper() const 00113 { 00114 return bbox.max_coord(max_span_coord()); 00115 } 00116 00117 inline FT 00118 max_tight_span_upper() const 00119 { 00120 return tbox.max_coord(max_tight_span_coord()); 00121 } 00122 00123 inline FT 00124 max_spread() const 00125 { 00126 return max_span_upper() - max_span_lower(); 00127 } 00128 00129 inline FT 00130 max_tight_spread() const 00131 { 00132 return max_tight_span_upper() - max_tight_span_lower(); 00133 } 00134 00135 00136 int 00137 max_tight_span_coord_balanced(FT Aspect_ratio) const 00138 { 00139 int cut_dim(-1); 00140 FT max_spread_points(FT(-1)); 00141 FT max_length = max_spread(); // length of longest side of box 00142 int dim = dimension(); 00143 for (int d=0; d<dim; d++) { 00144 FT length=bbox.max_coord(d)-bbox.min_coord(d); 00145 00146 if (FT(2)*max_length/length <= Aspect_ratio) { 00147 FT spread=tbox.max_coord(d)-tbox.min_coord(d); 00148 00149 if (spread > max_spread_points) { 00150 max_spread_points = spread; 00151 cut_dim = d; 00152 } 00153 } 00154 } 00155 // CGAL_assertion(cut_dim >= 0); 00156 return cut_dim; 00157 } 00158 00159 FT 00160 max_span_upper_without_dim(int d) const 00161 { 00162 FT max_span(FT(0)); 00163 int dim=dimension(); 00164 for (int i=0; i<dim; i++) { 00165 FT span = bbox.max_coord(i)-bbox.min_coord(i); 00166 if (d != i && span > max_span) max_span=span; 00167 } 00168 return max_span; 00169 } 00170 00171 FT 00172 balanced_fair(int d, FT Aspect_ratio) 00173 { 00174 FT small_piece = max_span_upper_without_dim(d) / Aspect_ratio; 00175 FT low_cut = bbox.min_coord(d) + small_piece; // lowest legal cut; 00176 FT high_cut = bbox.max_coord(d) - small_piece; //highest legal cut; 00177 // CGAL_assertion (high_cut >= low_cut); 00178 FT split_value = median(d); 00179 if (split_value < low_cut) split_value = low_cut; 00180 if (split_value > high_cut) split_value = high_cut; 00181 return split_value; 00182 } 00183 00184 FT 00185 balanced_sliding_fair(int d, FT Aspect_ratio) 00186 { 00187 FT small_piece = max_span_upper_without_dim(d) / Aspect_ratio; 00188 FT low_cut = bbox.min_coord(d) + small_piece; // lowest legal cut; 00189 FT high_cut = bbox.max_coord(d) - small_piece; //highest legal cut; 00190 // CGAL_assertion (high_cut >= low_cut); 00191 FT split_value = median(d); 00192 FT max_span_lower = tbox.min_coord(d); 00193 FT max_span_upper = tbox.max_coord(d); 00194 if (split_value < low_cut) split_value= max_span_lower; 00195 if (split_value > high_cut) split_value = max_span_upper; 00196 return split_value; 00197 } 00198 00199 // points 00200 inline unsigned int 00201 size() const 00202 { 00203 return *m_e - *m_b; 00204 } 00205 00206 inline iterator 00207 begin() const { 00208 return *m_b; 00209 } 00210 00211 inline iterator 00212 end() const 00213 { 00214 return *m_e; 00215 } 00216 00217 inline bool 00218 empty() const 00219 { 00220 return !m_b || !m_e || (*m_b == *m_e ) ; 00221 } 00222 00223 // building the container from a sequence of Point_d* 00224 Point_container(const int d, iterator begin, iterator end) : 00225 m_b(begin), m_e(end), bbox(d, begin, end), tbox(bbox) 00226 { 00227 built_coord = max_span_coord(); 00228 } 00229 00230 void 00231 set_range(iterator begin, iterator end) 00232 { 00233 m_b = begin; 00234 m_e = end; 00235 } 00236 00237 00238 // building an empty container 00239 Point_container(const int d) : 00240 bbox(d), tbox(d) 00241 {} 00242 00243 template <class Traits2> 00244 struct Cmp { 00245 typedef typename Traits2::FT FT; 00246 typedef typename Traits2::Point_d Point_d; 00247 typedef std::vector<Point_d*> Point_vector; 00248 00249 int split_coord; 00250 FT value; 00251 typename Traits2::Construct_cartesian_const_iterator_d construct_it; 00252 00253 Cmp(int s, FT c) 00254 : split_coord(s), value(c) 00255 {} 00256 00257 bool 00258 operator()(Point_d* pt) const 00259 { 00260 typename Traits2::Cartesian_const_iterator_d ptit; 00261 ptit = construct_it(*pt); 00262 return *(ptit+split_coord) < value; 00263 } 00264 }; 00265 00266 00267 template <class Traits2> 00268 struct Between { 00269 typedef typename Traits2::FT FT; 00270 typedef typename Traits2::Point_d Point_d; 00271 typedef std::vector<Point_d*> Point_vector; 00272 00273 int split_coord; 00274 FT low, high; 00275 typename Traits2::Construct_cartesian_const_iterator_d construct_it; 00276 00277 Between(int s, FT l, FT h) 00278 : split_coord(s), low(l), high(h) 00279 {} 00280 00281 bool 00282 operator()(Point_d* pt) const 00283 { 00284 typename Traits2::Cartesian_const_iterator_d ptit; 00285 ptit = construct_it(*pt); 00286 if(! ( *(ptit+split_coord) <= high ) ){ 00287 // std::cerr << "Point " << *pt << " exceeds " << high << " in dimension " << split_coord << std::endl; 00288 return false; 00289 } 00290 if(! ( *(ptit+split_coord) >= low ) ){ 00291 //std::cerr << "Point " << *pt << " below " << low << " in dimension " << split_coord << std::endl; 00292 return false; 00293 } 00294 return true; 00295 } 00296 }; 00297 00298 00299 void recompute_tight_bounding_box() 00300 { 00301 tbox.update_from_point_pointers(begin(), end()); 00302 } 00303 00304 00305 bool 00306 is_valid() const 00307 { 00308 if(empty()) return true; 00309 bool b = true; 00310 for (int i = 0; i < dimension(); i++){ 00311 CGAL_assertion( b = (b && (bbox.min_coord(i) <= tbox.min_coord(i)))); 00312 CGAL_assertion( b = (b && (bbox.max_coord(i) >= tbox.max_coord(i)))); 00313 00314 Between<Traits> between(i,tbox.min_coord(i), tbox.max_coord(i)); 00315 for(iterator it = begin(); it != end(); it++){ 00316 b = (b && between(*it)); 00317 } 00318 } 00319 return b; 00320 } 00321 00322 00323 // note that splitting is restricted to the built coordinate 00324 template <class Separator> 00325 void split(Point_container<Traits>& c, Separator& sep, 00326 bool sliding=false) 00327 { 00328 CGAL_assertion(dimension()==c.dimension()); 00329 CGAL_assertion(is_valid()); 00330 c.bbox=bbox; 00331 00332 const int split_coord = sep.cutting_dimension(); 00333 FT cutting_value = sep.cutting_value(); 00334 00335 built_coord=split_coord; 00336 c.built_coord=split_coord; 00337 00338 00339 typename Traits::Construct_cartesian_const_iterator_d construct_it; 00340 00341 Cmp<Traits> cmp(split_coord, cutting_value); 00342 iterator it = std::partition(begin(), end(), cmp); 00343 // now [begin,it) are lower and [it,end) are upper 00344 if (sliding) { // avoid empty lists 00345 00346 if (it == begin()) { 00347 iterator minelt = std::min_element(begin(),end(),comp_coord_val<Traits,int>(split_coord)); 00348 if(minelt != it){ 00349 std::iter_swap(minelt,it); 00350 } 00351 cutting_value = *(construct_it(**it)+split_coord); 00352 sep.set_cutting_value(cutting_value); 00353 it++; 00354 } 00355 if (it == end()) { 00356 iterator maxelt = std::max_element(begin(),end(),comp_coord_val<Traits,int>(split_coord)); 00357 it--; 00358 if(maxelt != it){ 00359 std::iter_swap(maxelt,it); 00360 } 00361 cutting_value = *(construct_it(**it)+split_coord); 00362 sep.set_cutting_value(cutting_value); 00363 } 00364 } 00365 00366 c.set_range(begin(), it); 00367 set_range(it, end()); 00368 // adjusting boxes 00369 bbox.set_lower_bound(split_coord, cutting_value); 00370 tbox.update_from_point_pointers(begin(), 00371 end()); 00372 c.bbox.set_upper_bound(split_coord, cutting_value); 00373 c.tbox.update_from_point_pointers(c.begin(), 00374 c.end()); 00375 CGAL_assertion(is_valid()); 00376 CGAL_assertion(c.is_valid()); 00377 } 00378 00379 00380 00381 template <class Traits2, class Value> 00382 struct comp_coord_val { 00383 00384 private: 00385 Value coord; 00386 00387 typedef typename Traits2::Point_d Point_d; 00388 public: 00389 comp_coord_val (const Value& coordinate) 00390 : coord(coordinate) 00391 {} 00392 00393 bool 00394 operator()(const Point_d *a, const Point_d *b) const 00395 { 00396 typename Traits2::Construct_cartesian_const_iterator_d construct_it; 00397 typename Traits2::Cartesian_const_iterator_d ait = construct_it(*a), 00398 bit = construct_it(*b); 00399 return *(ait+coord) < *(bit+coord); 00400 } 00401 }; 00402 00403 00404 FT 00405 median(const int split_coord) 00406 { 00407 typename Point_vector::iterator mid = begin() + (end() - begin())/2; 00408 std::nth_element(begin(), mid, end(),comp_coord_val<Traits,int>(split_coord)); 00409 00410 typename Traits::Construct_cartesian_const_iterator_d construct_it; 00411 typename Traits::Cartesian_const_iterator_d mpit = construct_it((*(*mid))); 00412 FT val1 = *(mpit+split_coord); 00413 mid++; 00414 mpit = construct_it((*(*mid))); 00415 FT val2 = *(mpit+split_coord); 00416 return (val1+val2)/FT(2); 00417 } 00418 00419 00420 00421 private: 00422 explicit Point_container() 00423 {} // disable default constructor 00424 00425 }; 00426 00427 template <class Point> 00428 std::ostream& 00429 operator<< (std::ostream& s, Point_container<Point>& c) 00430 { 00431 s << "Points container of size " << c.size() << "\n cell:"; 00432 s << c.bounding_box(); 00433 s << "\n minimal box enclosing points:"; s << c.tight_bounding_box(); 00434 return s; 00435 } 00436 00437 } // namespace CGAL 00438 00439 #endif // CGAL_POINT_CONTAINER_H 00440 00441