My Project
gcalc_tools.h
00001 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
00015 
00016 
00017 #ifndef GCALC_TOOLS_INCLUDED
00018 #define GCALC_TOOLS_INCLUDED
00019 
00020 #include "gcalc_slicescan.h"
00021 
00022 
00023 /*
00024   The Gcalc_function class objects are used to check for a binary relation.
00025   The relation can be constructed with the prefix notation using predicates as
00026         op_not (as !A)
00027         op_union ( A || B || C... )
00028         op_intersection ( A && B && C ... )
00029         op_symdifference ( A+B+C+... == 1 )
00030         op_difference ( A && !(B||C||..))
00031   with the calls of the add_operation(operation, n_operands) method.
00032   The relation is calculated over a set of shapes, that in turn have
00033   to be added with the add_new_shape() method. All the 'shapes' can
00034   be set to 0 with clear_shapes() method and single value
00035   can be changed with the invert_state() method.
00036   Then the value of the relation can be calculated with the count() method.
00037   Frequently used method is find_function(Gcalc_scan_iterator it) that
00038   iterates through the 'it' until the relation becomes TRUE.
00039 */
00040 
00041 class Gcalc_function
00042 {
00043 private:
00044   static const uint32 function_buffer_item_size= 4;
00045   static const uint32 shape_buffer_item_size= 4;
00046   String shapes_buffer;
00047   String function_buffer;
00048   const char *cur_func;
00049   int *i_states;
00050   uint32 cur_object_id;
00051   uint n_shapes;
00052   int count_internal();
00053 public:
00054 #ifndef DBUG_OFF
00055 
00058   static const char *op_name(int code);
00062   static const char *shape_name(int code);
00063 #endif
00064   enum op_type
00065   {
00066     op_shape= 0,
00067     op_not= 0x80000000,
00068     op_union= 0x10000000,
00069     op_intersection= 0x20000000,
00070     op_symdifference= 0x30000000,
00071     op_difference= 0x40000000,
00072     op_backdifference= 0x50000000,
00073     op_any= 0x70000000
00074   };
00075   enum shape_type
00076   {
00077     shape_point= 0,
00078     shape_line= 1,
00079     shape_polygon= 2,
00080     shape_hole= 3
00081   };
00082   Gcalc_function() : n_shapes(0) {}
00083   gcalc_shape_info add_new_shape(uint32 shape_id, shape_type shape_kind);
00084   /*
00085     Adds the leaf operation that returns the shape value.
00086     Also adds the shape to the list of operands.
00087   */
00088   int single_shape_op(shape_type shape_kind, gcalc_shape_info *si);
00089   void add_operation(op_type operation, uint32 n_operands);
00090   void add_not_operation(op_type operation, uint32 n_operands);
00091   uint32 get_next_operation_pos() { return function_buffer.length(); }
00095   void add_operands_to_op(uint32 operation_pos, uint32 n_operands);
00099   void set_operands_to_op(uint32 operation_pos, uint32 n_operands);
00100   void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; }
00101   int reserve_shape_buffer(uint n_shapes);
00102   int reserve_op_buffer(uint n_ops);
00103   uint get_nshapes() const { return n_shapes; }
00104   shape_type get_shape_kind(gcalc_shape_info si) const
00105   {
00106     return (shape_type) uint4korr(shapes_buffer.ptr() + (si*4));
00107   }
00108 
00109   void set_states(int *shape_states) { i_states= shape_states; }
00110   int alloc_states();
00111   void invert_state(gcalc_shape_info shape) { i_states[shape]^= 1; }
00112   int get_state(gcalc_shape_info shape) { return i_states[shape]; }
00113   int count()
00114   {
00115     cur_func= function_buffer.ptr();
00116     return count_internal();
00117   }
00118   void clear_state() { memset(i_states, 0, n_shapes * sizeof(int)); }
00119   void reset();
00120 
00121   int find_function(Gcalc_scan_iterator &scan_it);
00122 
00123 #ifndef DBUG_OFF
00124 
00130   void debug_print_function_buffer();
00131 #endif
00132 };
00133 
00134 
00135 /*
00136   Gcalc_operation_transporter class extends the Gcalc_shape_transporter.
00137   In addition to the parent's functionality, it fills the Gcalc_function
00138   object so it has the function that determines the proper shape.
00139   For example Multipolyline will be represented as an union of polylines.
00140 */
00141 
00142 class Gcalc_operation_transporter : public Gcalc_shape_transporter
00143 {
00144 protected:
00145   Gcalc_function *m_fn;
00146   gcalc_shape_info m_si;
00147 public:
00148   Gcalc_operation_transporter(Gcalc_function *fn, Gcalc_heap *heap) :
00149     Gcalc_shape_transporter(heap), m_fn(fn) {}
00150 
00151   int single_point(Gcalc_shape_status *st, double x, double y);
00152   int start_line(Gcalc_shape_status *st);
00153   int complete_line(Gcalc_shape_status *st);
00154   int start_poly(Gcalc_shape_status *st);
00155   int complete_poly(Gcalc_shape_status *st);
00156   int start_ring(Gcalc_shape_status *st);
00157   int complete_ring(Gcalc_shape_status *st);
00158   int add_point(Gcalc_shape_status *st, double x, double y);
00159   int start_collection(Gcalc_shape_status *st, int nshapes);
00160   int complete_collection(Gcalc_shape_status *st);
00161   int collection_add_item(Gcalc_shape_status *st_collection,
00162                           Gcalc_shape_status *st_item);
00163 };
00164 
00165 
00166 /*
00167    When we calculate the result of an spatial operation like
00168    Union or Intersection, we receive vertexes of the result
00169    one-by-one, and probably need to treat them in variative ways.
00170    So, the Gcalc_result_receiver class designed to get these
00171    vertexes and construct shapes/objects out of them.
00172    and to store the result in an appropriate format
00173 */
00174 
00175 class Gcalc_result_receiver
00176 {
00177   String buffer;
00178   uint32 n_points;
00179   Gcalc_function::shape_type common_shapetype;
00180   bool collection_result;
00181   uint32 n_shapes;
00182   uint32 n_holes;
00183 
00184   Gcalc_function::shape_type cur_shape;
00185   uint32 shape_pos;
00186   double first_x, first_y, prev_x, prev_y;
00187   double shape_area;
00188 public:
00189 
00190   class chunk_info
00191   {
00192   public:
00193     void *first_point;
00194     uint32 order;
00195     uint32 position;
00196     uint32 length;
00197     bool is_poly_hole;
00198 #ifndef DBUG_OFF
00199     inline void dbug_print() const;
00200 #endif
00201   };
00202 
00203   Gcalc_result_receiver() : collection_result(FALSE), n_shapes(0), n_holes(0)
00204     {}
00205   int start_shape(Gcalc_function::shape_type shape);
00206   int add_point(double x, double y);
00207   int complete_shape();
00208   int single_point(double x, double y);
00209   int done();
00210   void reset();
00211 
00212   const char *result() { return buffer.ptr(); }
00213   uint length() { return buffer.length(); }
00214   int get_nshapes() { return n_shapes; }
00215   int get_nholes() { return n_holes; }
00216   int get_result_typeid();
00217   uint32 position() { return buffer.length(); }
00218   int reorder_chunks(chunk_info *chunks, int nchunks);
00219 };
00220 
00221 
00222 /*
00223   Gcalc_operation_reducer class incapsulates the spatial
00224   operation functionality. It analyses the slices generated by
00225   the slicescan and calculates the shape of the result defined
00226   by some Gcalc_function.
00227 */
00228 
00229 class Gcalc_operation_reducer : public Gcalc_dyn_list
00230 {
00231 public:
00232   enum modes
00233   {
00234     /* Numeric values important here - careful with changing */
00235     default_mode= 0,
00236     prefer_big_with_holes= 1,
00237     polygon_selfintersections_allowed= 2,  /* allowed in the result */
00238     line_selfintersections_allowed= 4      /* allowed in the result */
00239   };
00240 
00241   Gcalc_operation_reducer(size_t blk_size=8192);
00242   void init(Gcalc_function *fn, modes mode= default_mode);
00243   Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode,
00244                        size_t blk_size=8192);
00245   int count_slice(Gcalc_scan_iterator *si);
00246   int count_all(Gcalc_heap *hp);
00247   int get_result(Gcalc_result_receiver *storage);
00248   void reset();
00249 
00250   class res_point : public Gcalc_dyn_list::Item
00251   {
00252     res_point *m_outer_poly;
00253   public:
00254     bool intersection_point;
00255     double x,y;
00256     res_point *up;
00257     res_point *down;
00258     res_point *glue;
00259     union
00260     {
00261       const Gcalc_heap::Info *pi; // is valid before get_result_thread()
00262       res_point *first_poly_node; // is valid after get_result_thread()
00263     };
00264     Gcalc_dyn_list::Item **prev_hook;
00265     res_point *get_next() { return (res_point *)next; }
00266     void set_outer_poly(res_point *p)
00267     {
00268       m_outer_poly= p;
00269       DBUG_PRINT("info", ("setting outer_poly of #%u to #%u",
00270                           item_id(),
00271                           m_outer_poly ? m_outer_poly->item_id() : 0));
00272     }
00273     res_point *get_outer_poly() { return m_outer_poly; }
00274   };
00275 
00276   class active_thread : public Gcalc_dyn_list::Item
00277   {
00278     res_point *m_thread_start;
00279   public:
00280     res_point *rp;
00281     int result_range;
00282     void init()
00283     {
00284       rp= m_thread_start= NULL;
00285       result_range= 0;
00286       DBUG_PRINT("info", ("setting m_thread_start of #%u to NULL (reset)",
00287                           item_id()));
00288     }
00289     active_thread *get_next() { return (active_thread *)next; }
00290     void set_thread_start(res_point *p)
00291     {
00292       DBUG_PRINT("info", ("setting m_thread_start of #%u to #%u",
00293                           item_id(), p ? p->item_id() : 0));
00294       m_thread_start= p;
00295     }
00296     res_point *thread_start() const { return m_thread_start; }
00297   };
00298 
00299 protected:
00300   Gcalc_function *m_fn;
00301   Gcalc_dyn_list::Item **m_res_hook;
00302   res_point *m_result;
00303   int m_mode;
00304 
00305   res_point *result_heap;
00306   active_thread *m_first_active_thread;
00307 
00308   res_point *add_res_point(const Gcalc_heap::Info *pi)
00309   {
00310     res_point *rp= new_res_point(pi, false);
00311     if (!rp)
00312       return NULL;
00313     DBUG_PRINT("info", ("add_res_point #%u: pi=(%g,%g,#%u)",
00314                         rp->item_id(), pi->x, pi->y, pi->shape));
00315     return rp;
00316   }
00317 
00318   res_point *add_res_i_point(const Gcalc_heap::Info *pi, double x, double y)
00319   {
00320     res_point *rp= new_res_point(pi, true);
00321     if (!rp)
00322       return NULL;
00323     DBUG_PRINT("info", ("add_res_i_point #%u: pi=(%g,%g,#%u) xy=(%g,%g)",
00324                         rp->item_id(), pi->x, pi->y, pi->shape, x, y));
00325     rp->x= x;
00326     rp->y= y;
00327     return rp;
00328   }
00329 
00330   res_point *add_res_single_point(const Gcalc_heap::Info *pi)
00331   {
00332     res_point *rp= new_res_point(pi, false);
00333     if (!rp)
00334       return NULL;
00335     DBUG_PRINT("info", ("add_res_single_point #%u: pi=(%g,%g,#%u)",
00336                         rp->item_id(), pi->x, pi->y, pi->shape));
00337     rp->x= pi->x;
00338     rp->y= pi->y;
00339     return rp;
00340   }
00341 
00342   active_thread *new_active_thread()
00343   {
00344     active_thread *tmp= (active_thread *) new_item();
00345     if (tmp)
00346       tmp->init();
00347     return tmp;
00348   }
00349 
00350 private:
00351 
00352   res_point *new_res_point(const Gcalc_heap::Info *pi,
00353                            bool intersection_point)
00354   {
00355     res_point *result= (res_point *) new_item();
00356     *m_res_hook= result;
00357     result->prev_hook= m_res_hook;
00358     m_res_hook= &result->next;
00359     result->pi= pi;
00360     result->intersection_point= intersection_point;
00361     return result;
00362   }
00363 
00364   int continue_range(active_thread *t, const Gcalc_heap::Info *p);
00365   int continue_i_range(active_thread *t, const Gcalc_heap::Info *p,
00366                        double x, double y);
00367   int start_range(active_thread *t, const Gcalc_heap::Info *p);
00368   int start_i_range(active_thread *t, const Gcalc_heap::Info *p,
00369                     double x, double y);
00370   int end_range(active_thread *t, const Gcalc_heap::Info *p);
00371   int end_i_range(active_thread *t, const Gcalc_heap::Info *p,
00372                   double x, double y);
00373   int start_couple(active_thread *t0, active_thread *t1,const Gcalc_heap::Info *p,
00374                      const active_thread *prev_range);
00375   int start_i_couple(active_thread *t0, active_thread *t1,
00376                      const Gcalc_heap::Info *p0,
00377                      const Gcalc_heap::Info *p1,
00378                      double x, double y,
00379                      const active_thread *prev_range);
00380   int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p);
00381   int end_i_couple(active_thread *t0, active_thread *t1,
00382                    const Gcalc_heap::Info *p0,
00383                    const Gcalc_heap::Info *p1,
00384                    double x, double y);
00385   int add_single_point(const Gcalc_heap::Info *p);
00386   int add_i_single_point(const Gcalc_heap::Info *p, double x, double y);
00387 
00388   int handle_lines_intersection(active_thread *t0, active_thread *t1,
00389                                 const Gcalc_heap::Info *p0,
00390                                 const Gcalc_heap::Info *p1,
00391                                 double x, double y);
00392   int handle_polygons_intersection(active_thread *t0, active_thread *t1,
00393                                    Gcalc_dyn_list::Item **t_hook,
00394                                    const Gcalc_heap::Info *p0,
00395                                    const Gcalc_heap::Info *p1,
00396                                    int prev_state, double x, double y,
00397                                    const active_thread *prev_range);
00398   int handle_line_polygon_intersection(active_thread *l,
00399                                        const Gcalc_heap::Info *pl,
00400                                        int line_state, int poly_state,
00401                                        double x, double y);
00402 
00403   int get_single_result(res_point *res, Gcalc_result_receiver *storage);
00404   int get_result_thread(res_point *cur, Gcalc_result_receiver *storage,
00405                         int move_upward);
00406   int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage);
00407   int get_line_result(res_point *cur, Gcalc_result_receiver *storage);
00408 
00409   void free_result(res_point *res);
00410 };
00411 
00412 #endif /*GCALC_TOOLS_INCLUDED*/
00413 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines