My Project
gcalc_slicescan.h
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines