1 /* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
2    Copyright (C) 2011 Monty Program Ab.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
16 
17 
18 #ifndef GCALC_TOOLS_INCLUDED
19 #define GCALC_TOOLS_INCLUDED
20 
21 #include "gcalc_slicescan.h"
22 #include "sql_string.h"
23 
24 
25 /*
26   The Gcalc_function class objects are used to check for a binary relation.
27   The relation can be constructed with the prefix notation using predicates as
28         op_not (as !A)
29         op_union ( A || B || C... )
30         op_intersection ( A && B && C ... )
31         op_symdifference ( A+B+C+... == 1 )
32         op_difference ( A && !(B||C||..))
33   with the calls of the add_operation(operation, n_operands) method.
34   The relation is calculated over a set of shapes, that in turn have
35   to be added with the add_new_shape() method. All the 'shapes' can
36   be set to 0 with clear_shapes() method and single value
37   can be changed with the invert_state() method.
38   Then the value of the relation can be calculated with the count() method.
39   Frequently used method is find_function(Gcalc_scan_iterator it) that
40   iterates through the 'it' until the relation becomes TRUE.
41 */
42 
43 class Gcalc_function
44 {
45 private:
46   String shapes_buffer;
47   String function_buffer;
48   int *i_states;
49   int *b_states;
50   uint32 cur_object_id;
51   uint n_shapes;
52   int count_internal(const char *cur_func, uint set_type,
53                      const char **end);
54 public:
55   enum value
56   {
57     v_empty=   0x0000000,
58     v_find_t=  0x1000000,
59     v_find_f=  0x2000000,
60     v_t_found= 0x3000000,
61     v_f_found= 0x4000000,
62     v_mask=    0x7000000
63   };
64   enum op_type
65   {
66     op_not=           0x80000000,
67     op_shape=         0x00000000,
68     op_union=         0x10000000,
69     op_intersection=  0x20000000,
70     op_symdifference= 0x30000000,
71     op_difference=    0x40000000,
72     op_repeat=        0x50000000,
73     op_border=        0x60000000,
74     op_internals=     0x70000000,
75     op_false=         0x08000000,
76     op_any=           0x78000000 /* The mask to get any of the operations */
77   };
78   enum shape_type
79   {
80     shape_point= 0,
81     shape_line= 1,
82     shape_polygon= 2,
83     shape_hole= 3
84   };
85   enum count_result
86   {
87     result_false= 0,
88     result_true= 1,
89     result_unknown= 2
90   };
91   Gcalc_function() : n_shapes(0) {}
92   gcalc_shape_info add_new_shape(uint32 shape_id, shape_type shape_kind);
93   /*
94     Adds the leaf operation that returns the shape value.
95     Also adds the shape to the list of operands.
96   */
97   int single_shape_op(shape_type shape_kind, gcalc_shape_info *si);
98   void add_operation(uint operation, uint32 n_operands);
99   void add_not_operation(op_type operation, uint32 n_operands);
100   uint32 get_next_expression_pos() { return function_buffer.length(); }
101   void add_operands_to_op(uint32 operation_pos, uint32 n_operands);
102   int repeat_expression(uint32 exp_pos);
103   void set_cur_obj(uint32 cur_obj) { cur_object_id= cur_obj; }
104   int reserve_shape_buffer(uint n_shapes);
105   int reserve_op_buffer(uint n_ops);
106   uint get_nshapes() const { return n_shapes; }
107   shape_type get_shape_kind(gcalc_shape_info si) const
108   {
109     return (shape_type) uint4korr(shapes_buffer.ptr() + (si*4));
110   }
111 
112   void set_states(int *shape_states) { i_states= shape_states; }
113   int alloc_states();
114   void invert_i_state(gcalc_shape_info shape) { i_states[shape]^= 1; }
115   void set_i_state(gcalc_shape_info shape) { i_states[shape]= 1; }
116   void clear_i_state(gcalc_shape_info shape) { i_states[shape]= 0; }
117   void set_b_state(gcalc_shape_info shape) { b_states[shape]= 1; }
118   void clear_b_state(gcalc_shape_info shape) { b_states[shape]= 0; }
119   int get_state(gcalc_shape_info shape)
120     { return i_states[shape] | b_states[shape]; }
121   int get_i_state(gcalc_shape_info shape) { return i_states[shape]; }
122   int get_b_state(gcalc_shape_info shape) { return b_states[shape]; }
123   int count()
124     { return count_internal(function_buffer.ptr(), 0, 0); }
125   int count_last()
126     { return count_internal(function_buffer.ptr(), 1, 0); }
127   void clear_i_states();
128   void clear_b_states();
129   void reset();
130 
131   int check_function(Gcalc_scan_iterator &scan_it);
132 };
133 
134 
135 /*
136   Gcalc_operation_transporter class extends the Gcalc_shape_transporter.
137   In addition to the parent's functionality, it fills the Gcalc_function
138   object so it has the function that determines the proper shape.
139   For example Multipolyline will be represented as an union of polylines.
140 */
141 
142 class Gcalc_operation_transporter : public Gcalc_shape_transporter
143 {
144 protected:
145   Gcalc_function *m_fn;
146   gcalc_shape_info m_si;
147 public:
148   Gcalc_operation_transporter(Gcalc_function *fn, Gcalc_heap *heap) :
149     Gcalc_shape_transporter(heap), m_fn(fn) {}
150 
151   int single_point(double x, double y);
152   int start_line();
153   int complete_line();
154   int start_poly();
155   int complete_poly();
156   int start_ring();
157   int complete_ring();
158   int add_point(double x, double y);
159   int start_collection(int n_objects);
160   int empty_shape();
161 };
162 
163 
164 /*
165    When we calculate the result of an spatial operation like
166    Union or Intersection, we receive vertexes of the result
167    one-by-one, and probably need to treat them in variative ways.
168    So, the Gcalc_result_receiver class designed to get these
169    vertexes and construct shapes/objects out of them.
170    and to store the result in an appropriate format
171 */
172 
173 class Gcalc_result_receiver
174 {
175   String buffer;
176   uint32 n_points;
177   Gcalc_function::shape_type common_shapetype;
178   bool collection_result;
179   uint32 n_shapes;
180   uint32 n_holes;
181 
182   Gcalc_function::shape_type cur_shape;
183   uint32 shape_pos;
184   double first_x, first_y, prev_x, prev_y;
185   double shape_area;
186 public:
187   Gcalc_result_receiver() : collection_result(FALSE), n_shapes(0), n_holes(0)
188     {}
189   int start_shape(Gcalc_function::shape_type shape);
190   int add_point(double x, double y);
191   int complete_shape();
192   int single_point(double x, double y);
193   int done();
194   void reset();
195 
196   const char *result() { return buffer.ptr(); }
197   uint length() { return buffer.length(); }
198   int get_nshapes() { return n_shapes; }
199   int get_nholes() { return n_holes; }
200   int get_result_typeid();
201   uint32 position() { return buffer.length(); }
202   int move_hole(uint32 dest_position, uint32 source_position,
203                 uint32 *position_shift);
204 };
205 
206 
207 /*
208   Gcalc_operation_reducer class incapsulates the spatial
209   operation functionality. It analyses the slices generated by
210   the slicescan and calculates the shape of the result defined
211   by some Gcalc_function.
212 */
213 
214 class Gcalc_operation_reducer : public Gcalc_dyn_list
215 {
216 public:
217   enum modes
218   {
219     /* Numeric values important here - careful with changing */
220     default_mode= 0,
221     prefer_big_with_holes= 1,
222     polygon_selfintersections_allowed= 2,  /* allowed in the result */
223     line_selfintersections_allowed= 4      /* allowed in the result */
224   };
225 
226   Gcalc_operation_reducer(size_t blk_size=8192);
227   Gcalc_operation_reducer(const Gcalc_operation_reducer &gor);
228   void init(Gcalc_function *fn, modes mode= default_mode);
229   Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode,
230 		       size_t blk_size=8192);
231   GCALC_DECL_TERMINATED_STATE(killed)
232   int count_slice(Gcalc_scan_iterator *si);
233   int count_all(Gcalc_heap *hp);
234   int get_result(Gcalc_result_receiver *storage);
235   void reset();
236 
237 #ifndef GCALC_DBUG_OFF
238   int n_res_points;
239 #endif /*GCALC_DBUG_OFF*/
240   class res_point : public Gcalc_dyn_list::Item
241   {
242   public:
243     int intersection_point;
244     union
245     {
246       const Gcalc_heap::Info *pi;
247       res_point *first_poly_node;
248     };
249     union
250     {
251       res_point *outer_poly;
252       uint32 poly_position;
253     };
254     res_point *up;
255     res_point *down;
256     res_point *glue;
257     Gcalc_function::shape_type type;
258     Gcalc_dyn_list::Item **prev_hook;
259 #ifndef GCALC_DBUG_OFF
260     int point_n;
261 #endif /*GCALC_DBUG_OFF*/
262     void set(const Gcalc_scan_iterator *si);
263     res_point *get_next() { return (res_point *)next; }
264   };
265 
266   class active_thread : public Gcalc_dyn_list::Item
267   {
268   public:
269     res_point *rp;
270     res_point *thread_start;
271 
272     const Gcalc_heap::Info *p1, *p2;
273     res_point *enabled() { return rp; }
274     active_thread *get_next() { return (active_thread *)next; }
275   };
276 
277   class poly_instance : public Gcalc_dyn_list::Item
278   {
279   public:
280     uint32 *after_poly_position;
281     poly_instance *get_next() { return (poly_instance *)next; }
282   };
283 
284   class line : public Gcalc_dyn_list::Item
285   {
286   public:
287     active_thread *t;
288     int incoming;
289     const Gcalc_scan_iterator::point *p;
290     line *get_next() { return (line *)next; }
291   };
292 
293   class poly_border : public Gcalc_dyn_list::Item
294   {
295   public:
296     active_thread *t;
297     int incoming;
298     int prev_state;
299     const Gcalc_scan_iterator::point *p;
300     poly_border *get_next() { return (poly_border *)next; }
301   };
302 
303   line *m_lines;
304   Gcalc_dyn_list::Item **m_lines_hook;
305   poly_border *m_poly_borders;
306   Gcalc_dyn_list::Item **m_poly_borders_hook;
307   line *new_line() { return (line *) new_item(); }
308   poly_border *new_poly_border() { return (poly_border *) new_item(); }
309   int add_line(int incoming, active_thread *t,
310                const Gcalc_scan_iterator::point *p);
311   int add_poly_border(int incoming, active_thread *t, int prev_state,
312                       const Gcalc_scan_iterator::point *p);
313 
314 protected:
315   Gcalc_function *m_fn;
316   Gcalc_dyn_list::Item **m_res_hook;
317   res_point *m_result;
318   int m_mode;
319 
320   res_point *result_heap;
321   active_thread *m_first_active_thread;
322 
323   res_point *add_res_point(Gcalc_function::shape_type type);
324   active_thread *new_active_thread() { return (active_thread *)new_item(); }
325 
326   poly_instance *new_poly() { return (poly_instance *) new_item(); }
327 
328 private:
329   int start_line(active_thread *t, const Gcalc_scan_iterator::point *p,
330                  const Gcalc_scan_iterator *si);
331   int end_line(active_thread *t, const Gcalc_scan_iterator *si);
332   int connect_threads(int incoming_a, int incoming_b,
333                       active_thread *ta, active_thread *tb,
334                       const Gcalc_scan_iterator::point *pa,
335                       const Gcalc_scan_iterator::point *pb,
336                       active_thread *prev_range,
337                       const Gcalc_scan_iterator *si,
338                       Gcalc_function::shape_type s_t);
339   int add_single_point(const Gcalc_scan_iterator *si);
340   poly_border *get_pair_border(poly_border *b1);
341   int continue_range(active_thread *t, const Gcalc_heap::Info *p,
342                      const Gcalc_heap::Info *p_next);
343   int continue_i_range(active_thread *t,
344                        const Gcalc_heap::Info *ii);
345   int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p);
346   int get_single_result(res_point *res, Gcalc_result_receiver *storage);
347   int get_result_thread(res_point *cur, Gcalc_result_receiver *storage,
348 			int move_upward, res_point *first_poly_node);
349   int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage,
350                          res_point *first_poly_node);
351   int get_line_result(res_point *cur, Gcalc_result_receiver *storage);
352 
353   void free_result(res_point *res);
354 };
355 
356 #endif /*GCALC_TOOLS_INCLUDED*/
357 
358