My Project
|
00001 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. reserved. 00002 reserved. 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; version 2 of the License. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 00016 00017 00018 #ifndef GCALC_SLICESCAN_INCLUDED 00019 #define GCALC_SLICESCAN_INCLUDED 00020 00021 00022 /* 00023 Gcalc_dyn_list class designed to manage long lists of same-size objects 00024 with the possible efficiency. 00025 It allocates fixed-size blocks of memory (blk_size specified at the time 00026 of creation). When new object is added to the list, it occupies part of 00027 this block until it's full. Then the new block is allocated. 00028 Freed objects are chained to the m_free list, and if it's not empty, the 00029 newly added object is taken from this list instead the block. 00030 */ 00031 00032 class Gcalc_dyn_list 00033 { 00034 #ifndef DBUG_OFF 00035 uint m_last_item_id; 00036 #endif 00037 public: 00038 class Item 00039 { 00040 #ifndef DBUG_OFF 00041 uint m_item_id; 00042 public: 00043 uint item_id() const { return m_item_id; } 00044 void set_item_id(uint id) { m_item_id= id; } 00045 #endif 00046 public: 00047 Item *next; 00048 }; 00049 00050 Gcalc_dyn_list(size_t blk_size, size_t sizeof_item); 00051 ~Gcalc_dyn_list(); 00052 Item *new_item() 00053 { 00054 Item *result; 00055 if (!m_free && alloc_new_blk()) 00056 return NULL; 00057 00058 DBUG_ASSERT(m_free); 00059 result= m_free; 00060 m_free= m_free->next; 00061 00062 #ifndef DBUG_OFF 00063 result->set_item_id(++m_last_item_id); 00064 #endif 00065 result->next= NULL; 00066 return result; 00067 } 00068 inline void free_item(Item *item) 00069 { 00070 item->next= m_free; 00071 m_free= item; 00072 } 00073 inline void free_list(Item *list, Item **hook) 00074 { 00075 *hook= m_free; 00076 m_free= list; 00077 } 00078 00079 void free_list(Item *list) 00080 { 00081 Item **hook= &list; 00082 while (*hook) 00083 hook= &(*hook)->next; 00084 free_list(list, hook); 00085 } 00086 00087 void reset(); 00088 void cleanup(); 00089 00090 protected: 00091 size_t m_blk_size; 00092 size_t m_sizeof_item; 00093 unsigned int m_points_per_blk; 00094 void *m_first_blk; 00095 void **m_blk_hook; 00096 Item *m_free; 00097 Item *m_keep; 00098 00099 bool alloc_new_blk(); 00100 void format_blk(void* block); 00101 inline Item *ptr_add(Item *ptr, int n_items) 00102 { 00103 return (Item *)(((char*)ptr) + n_items * m_sizeof_item); 00104 } 00105 }; 00106 00107 typedef uint gcalc_shape_info; 00108 00109 /* 00110 Gcalc_heap represents the 'dynamic list' of Info objects, that 00111 contain information about vertexes of all the shapes that take 00112 part in some spatial calculation. Can become quite long. 00113 After filled, the list is usually sorted and then walked through 00114 in the slicescan algorithm. 00115 The Gcalc_heap and the algorithm can only operate with two 00116 kinds of shapes - polygon and polyline. So all the spatial 00117 objects should be represented as sets of these two. 00118 */ 00119 00120 class Gcalc_heap : public Gcalc_dyn_list 00121 { 00122 public: 00123 class Info : public Gcalc_dyn_list::Item 00124 { 00125 public: 00126 gcalc_shape_info shape; 00127 Info *left; 00128 Info *right; 00129 double x,y; 00130 00131 inline bool is_bottom() const { return !left; } 00132 inline Info *get_next() { return (Info *)next; } 00133 inline const Info *get_next() const { return (const Info *)next; } 00134 #ifndef DBUG_OFF 00135 inline void dbug_print() const; 00136 #endif 00137 }; 00138 00139 Gcalc_heap(size_t blk_size=8192) : 00140 Gcalc_dyn_list(blk_size, sizeof(Info)), m_hook(&m_first), m_n_points(0) {} 00141 Info *new_point_info(double x, double y, gcalc_shape_info shape) 00142 { 00143 Info *result= (Info *)new_item(); 00144 if (!result) 00145 return NULL; 00146 *m_hook= result; 00147 m_hook= &result->next; 00148 m_n_points++; 00149 result->x= x; 00150 result->y= y; 00151 result->shape= shape; 00152 return result; 00153 } 00154 void prepare_operation(); 00155 inline bool ready() const { return m_hook == NULL; } 00156 Info *get_first() { return (Info *)m_first; } 00157 const Info *get_first() const { return (const Info *)m_first; } 00158 Gcalc_dyn_list::Item **get_last_hook() { return m_hook; } 00159 void reset(); 00160 private: 00161 Gcalc_dyn_list::Item *m_first; 00162 Gcalc_dyn_list::Item **m_hook; 00163 int m_n_points; 00164 }; 00165 00166 00172 class Gcalc_shape_status 00173 { 00174 public: 00175 int m_nshapes; 00176 int m_last_shape_pos; 00177 Gcalc_shape_status() 00178 { 00179 m_nshapes= 0; // How many shapes have been collected 00180 m_last_shape_pos= 0; // Last shape start position in function_buffer 00181 } 00182 }; 00183 00184 00185 /* 00186 the spatial object has to be represented as a set of 00187 simple polygones and polylines to be sent to the slicescan. 00188 00189 Gcalc_shape_transporter class and his descendants are used to 00190 simplify storing the information about the shape into necessary structures. 00191 This base class only fills the Gcalc_heap with the information about 00192 shapes and vertices. 00193 00194 Normally the Gcalc_shape_transporter family object is sent as a parameter 00195 to the 'get_shapes' method of an 'spatial' object so it can pass 00196 the spatial information about itself. The virtual methods are 00197 treating this data in a way the caller needs. 00198 */ 00199 00200 class Gcalc_shape_transporter 00201 { 00202 private: 00203 Gcalc_heap::Info *m_first; 00204 Gcalc_heap::Info *m_prev; 00205 int m_shape_started; 00206 void int_complete(); 00207 protected: 00208 Gcalc_heap *m_heap; 00209 int int_single_point(gcalc_shape_info Info, double x, double y); 00210 int int_add_point(gcalc_shape_info Info, double x, double y); 00211 void int_start_line() 00212 { 00213 DBUG_ASSERT(!m_shape_started); 00214 m_shape_started= 1; 00215 m_first= m_prev= NULL; 00216 } 00217 void int_complete_line() 00218 { 00219 DBUG_ASSERT(m_shape_started== 1); 00220 int_complete(); 00221 m_shape_started= 0; 00222 } 00223 void int_start_ring() 00224 { 00225 DBUG_ASSERT(m_shape_started== 2); 00226 m_shape_started= 3; 00227 m_first= m_prev= NULL; 00228 } 00229 void int_complete_ring() 00230 { 00231 DBUG_ASSERT(m_shape_started== 3); 00232 int_complete(); 00233 m_shape_started= 2; 00234 } 00235 void int_start_poly() 00236 { 00237 DBUG_ASSERT(!m_shape_started); 00238 m_shape_started= 2; 00239 } 00240 void int_complete_poly() 00241 { 00242 DBUG_ASSERT(m_shape_started== 2); 00243 m_shape_started= 0; 00244 } 00245 bool line_started() { return m_shape_started == 1; }; 00246 public: 00247 Gcalc_shape_transporter(Gcalc_heap *heap) : 00248 m_shape_started(0), m_heap(heap) {} 00249 00250 /* Transformation event methods */ 00251 virtual int single_point(Gcalc_shape_status *st, double x, double y)=0; 00252 virtual int start_line(Gcalc_shape_status *st)=0; 00253 virtual int complete_line(Gcalc_shape_status *st)=0; 00254 virtual int start_poly(Gcalc_shape_status *st)=0; 00255 virtual int complete_poly(Gcalc_shape_status *st)=0; 00256 virtual int start_ring(Gcalc_shape_status *st)=0; 00257 virtual int complete_ring(Gcalc_shape_status *st)=0; 00258 virtual int add_point(Gcalc_shape_status *st, double x, double y)=0; 00259 virtual int start_collection(Gcalc_shape_status *st, int nshapes)= 0; 00260 virtual int complete_collection(Gcalc_shape_status *st)= 0; 00261 virtual int collection_add_item(Gcalc_shape_status *st_collection, 00262 Gcalc_shape_status *st_item)= 0; 00263 int start_simple_poly(Gcalc_shape_status *st) 00264 { 00265 return start_poly(st) || start_ring(st); 00266 } 00267 int complete_simple_poly(Gcalc_shape_status *st) 00268 { 00269 return complete_ring(st) || complete_poly(st); 00270 } 00271 00272 /* 00273 Filter methods: in some cases we are not interested in certain 00274 geometry types and can skip them during transformation instead 00275 of inserting "no operation" actions. 00276 For example, ST_Buffer() called with a negative distance argument 00277 does not need any Points and LineStrings. 00278 */ 00279 virtual bool skip_point() const { return false; } 00280 virtual bool skip_line_string() const { return false; } 00281 virtual bool skip_poly() const { return false; } 00282 00283 virtual ~Gcalc_shape_transporter() {} 00284 }; 00285 00286 00287 enum Gcalc_scan_events 00288 { 00289 scev_point= 1, /* Just a new point in thread */ 00290 scev_thread= 2, /* Start of the new thread */ 00291 scev_two_threads= 4, /* A couple of new threads started */ 00292 scev_intersection= 8, /* Intersection happened */ 00293 scev_end= 16, /* Single thread finished */ 00294 scev_two_ends= 32, /* A couple of threads finished */ 00295 scev_single_point= 64 /* Got single point */ 00296 }; 00297 00298 #ifndef DBUG_OFF 00299 const char *Gcalc_scan_event_name(enum Gcalc_scan_events event); 00300 #endif 00301 00302 typedef int sc_thread_id; 00303 00304 /* 00305 Gcalc_scan_iterator incapsulates the slisescan algorithm. 00306 It takes filled Gcalc_heap as an datasource. Then can be 00307 iterated trought the vertexes and intersection points with 00308 the step() method. After the 'step()' one usually observes 00309 the current 'slice' to do the necessary calculations, like 00310 looking for intersections, calculating the area, whatever. 00311 */ 00312 00313 class Gcalc_scan_iterator : public Gcalc_dyn_list 00314 { 00315 public: 00316 class point : public Gcalc_dyn_list::Item 00317 { 00318 public: 00319 double x; 00320 double dx_dy; 00321 int horiz_dir; 00322 Gcalc_heap::Info *pi; 00323 Gcalc_heap::Info *next_pi; 00324 sc_thread_id thread; 00325 const point *precursor; /* used as a temporary field */ 00326 00327 inline const point *c_get_next() const 00328 { return (const point *)next; } 00329 inline bool is_bottom() const { return pi->is_bottom(); } 00330 gcalc_shape_info get_shape() const { return pi->shape; } 00331 inline point *get_next() { return (point *)next; } 00332 inline const point *get_next() const { return (const point *)next; } 00333 00334 /* copies all but 'next' 'x' and 'precursor' */ 00335 void copy_core(const point *from) 00336 { 00337 dx_dy= from->dx_dy; 00338 horiz_dir= from->horiz_dir; 00339 pi= from->pi; 00340 next_pi= from->next_pi; 00341 thread= from->thread; 00342 } 00343 #ifndef DBUG_OFF 00344 inline void dbug_print_slice(double y, enum Gcalc_scan_events event) const; 00345 #endif 00346 }; 00347 00348 class intersection : public Gcalc_dyn_list::Item 00349 { 00350 public: 00351 sc_thread_id thread_a; 00352 sc_thread_id thread_b; 00353 double x; 00354 double y; 00355 inline intersection *get_next() { return (intersection *)next; } 00356 }; 00357 00358 public: 00359 Gcalc_scan_iterator(size_t blk_size= 8192); 00360 00361 void init(Gcalc_heap *points); /* Iterator can be reused */ 00362 void reset(); 00363 int step() 00364 { 00365 DBUG_ASSERT(more_points()); 00366 return m_cur_intersection ? intersection_scan() : normal_scan(); 00367 } 00368 00369 inline Gcalc_heap::Info *more_points() { return m_cur_pi; } 00370 inline bool more_trapezoids() 00371 { return m_cur_pi && m_cur_pi->next; } 00372 00373 inline Gcalc_scan_events get_event() const { return m_event0; } 00374 inline const point *get_event_position() const 00375 { return m_event_position0; } 00376 inline const point *get_b_slice() const { return m_slice0; } 00377 inline const point *get_t_slice() const { return m_slice1; } 00378 inline double get_h() const { return m_h; } 00379 inline double get_y() const { return m_y0; } 00380 00381 private: 00382 Gcalc_heap::Info *m_cur_pi; 00383 point *m_slice0; 00384 point *m_slice1; 00385 point *m_sav_slice; 00386 intersection *m_intersections; 00387 int m_n_intersections; 00388 intersection *m_cur_intersection; 00389 point **m_pre_intersection_hook; 00390 double m_h; 00391 double m_y0; 00392 double m_y1; 00393 double m_sav_y; 00394 bool m_next_is_top_point; 00395 unsigned int m_bottom_points_count; 00396 sc_thread_id m_cur_thread; 00397 Gcalc_scan_events m_event0, m_event1; 00398 point *m_event_position0; 00399 point *m_event_position1; 00400 00401 int normal_scan(); 00402 int intersection_scan(); 00403 void sort_intersections(); 00404 int handle_intersections(); 00405 int insert_top_point(); 00406 int add_intersection(const point *a, const point *b, 00407 int isc_kind, Gcalc_dyn_list::Item ***p_hook); 00408 int find_intersections(); 00409 int pop_suitable_intersection(); 00410 00411 intersection *new_intersection() 00412 { 00413 return (intersection *)new_item(); 00414 } 00415 point *new_slice_point() 00416 { 00417 return (point *)new_item(); 00418 } 00419 point *new_slice(point *example); 00420 }; 00421 00422 00423 /* 00424 Gcalc_trapezoid_iterator simplifies the calculations on 00425 the current slice of the Gcalc_scan_iterator. 00426 One can walk through the trapezoids formed between 00427 previous and current slices. 00428 */ 00429 00430 class Gcalc_trapezoid_iterator 00431 { 00432 protected: 00433 const Gcalc_scan_iterator::point *sp0; 00434 const Gcalc_scan_iterator::point *sp1; 00435 public: 00436 Gcalc_trapezoid_iterator(const Gcalc_scan_iterator *scan_i) : 00437 sp0(scan_i->get_b_slice()), 00438 sp1(scan_i->get_t_slice()) 00439 {} 00440 00441 inline bool more() const { return sp1 && sp1->next; } 00442 00443 const Gcalc_scan_iterator::point *lt() const { return sp1; } 00444 const Gcalc_scan_iterator::point *lb() const { return sp0; } 00445 const Gcalc_scan_iterator::point *rb() const 00446 { 00447 const Gcalc_scan_iterator::point *result= sp0; 00448 while ((result= result->c_get_next())->is_bottom()) 00449 {} 00450 return result; 00451 } 00452 const Gcalc_scan_iterator::point *rt() const 00453 { return sp1->c_get_next(); } 00454 00455 void operator++() 00456 { 00457 sp0= rb(); 00458 sp1= rt(); 00459 } 00460 }; 00461 00462 00463 /* 00464 Gcalc_point_iterator simplifies the calculations on 00465 the current slice of the Gcalc_scan_iterator. 00466 One can walk through the points on the current slice. 00467 */ 00468 00469 class Gcalc_point_iterator 00470 { 00471 protected: 00472 const Gcalc_scan_iterator::point *sp; 00473 public: 00474 Gcalc_point_iterator(const Gcalc_scan_iterator *scan_i): 00475 sp(scan_i->get_b_slice()) 00476 {} 00477 00478 inline bool more() const { return sp != NULL; } 00479 inline void operator++() { sp= sp->c_get_next(); } 00480 inline const Gcalc_scan_iterator::point *point() const { return sp; } 00481 inline const Gcalc_heap::Info *get_pi() const { return sp->pi; } 00482 inline gcalc_shape_info get_shape() const { return sp->get_shape(); } 00483 inline double get_x() const { return sp->x; } 00484 }; 00485 00486 #endif /*GCALC_SLICESCAN_INCLUDED*/ 00487