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 02111-1301 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 | void init(Gcalc_function *fn, modes mode= default_mode); |
228 | Gcalc_operation_reducer(Gcalc_function *fn, modes mode= default_mode, |
229 | size_t blk_size=8192); |
230 | GCALC_DECL_TERMINATED_STATE(killed) |
231 | int count_slice(Gcalc_scan_iterator *si); |
232 | int count_all(Gcalc_heap *hp); |
233 | int get_result(Gcalc_result_receiver *storage); |
234 | void reset(); |
235 | |
236 | #ifndef GCALC_DBUG_OFF |
237 | int n_res_points; |
238 | #endif /*GCALC_DBUG_OFF*/ |
239 | class res_point : public Gcalc_dyn_list::Item |
240 | { |
241 | public: |
242 | int intersection_point; |
243 | union |
244 | { |
245 | const Gcalc_heap::Info *pi; |
246 | res_point *first_poly_node; |
247 | }; |
248 | union |
249 | { |
250 | res_point *outer_poly; |
251 | uint32 poly_position; |
252 | }; |
253 | res_point *up; |
254 | res_point *down; |
255 | res_point *glue; |
256 | Gcalc_function::shape_type type; |
257 | Gcalc_dyn_list::Item **prev_hook; |
258 | #ifndef GCALC_DBUG_OFF |
259 | int point_n; |
260 | #endif /*GCALC_DBUG_OFF*/ |
261 | void set(const Gcalc_scan_iterator *si); |
262 | res_point *get_next() { return (res_point *)next; } |
263 | }; |
264 | |
265 | class active_thread : public Gcalc_dyn_list::Item |
266 | { |
267 | public: |
268 | res_point *rp; |
269 | res_point *thread_start; |
270 | |
271 | const Gcalc_heap::Info *p1, *p2; |
272 | res_point *enabled() { return rp; } |
273 | active_thread *get_next() { return (active_thread *)next; } |
274 | }; |
275 | |
276 | class poly_instance : public Gcalc_dyn_list::Item |
277 | { |
278 | public: |
279 | uint32 *after_poly_position; |
280 | poly_instance *get_next() { return (poly_instance *)next; } |
281 | }; |
282 | |
283 | class line : public Gcalc_dyn_list::Item |
284 | { |
285 | public: |
286 | active_thread *t; |
287 | int incoming; |
288 | const Gcalc_scan_iterator::point *p; |
289 | line *get_next() { return (line *)next; } |
290 | }; |
291 | |
292 | class poly_border : public Gcalc_dyn_list::Item |
293 | { |
294 | public: |
295 | active_thread *t; |
296 | int incoming; |
297 | int prev_state; |
298 | const Gcalc_scan_iterator::point *p; |
299 | poly_border *get_next() { return (poly_border *)next; } |
300 | }; |
301 | |
302 | line *m_lines; |
303 | Gcalc_dyn_list::Item **m_lines_hook; |
304 | poly_border *m_poly_borders; |
305 | Gcalc_dyn_list::Item **m_poly_borders_hook; |
306 | line *new_line() { return (line *) new_item(); } |
307 | poly_border *new_poly_border() { return (poly_border *) new_item(); } |
308 | int add_line(int incoming, active_thread *t, |
309 | const Gcalc_scan_iterator::point *p); |
310 | int add_poly_border(int incoming, active_thread *t, int prev_state, |
311 | const Gcalc_scan_iterator::point *p); |
312 | |
313 | protected: |
314 | Gcalc_function *m_fn; |
315 | Gcalc_dyn_list::Item **m_res_hook; |
316 | res_point *m_result; |
317 | int m_mode; |
318 | |
319 | res_point *result_heap; |
320 | active_thread *m_first_active_thread; |
321 | |
322 | res_point *add_res_point(Gcalc_function::shape_type type); |
323 | active_thread *new_active_thread() { return (active_thread *)new_item(); } |
324 | |
325 | poly_instance *new_poly() { return (poly_instance *) new_item(); } |
326 | |
327 | private: |
328 | int start_line(active_thread *t, const Gcalc_scan_iterator::point *p, |
329 | const Gcalc_scan_iterator *si); |
330 | int end_line(active_thread *t, const Gcalc_scan_iterator *si); |
331 | int connect_threads(int incoming_a, int incoming_b, |
332 | active_thread *ta, active_thread *tb, |
333 | const Gcalc_scan_iterator::point *pa, |
334 | const Gcalc_scan_iterator::point *pb, |
335 | active_thread *prev_range, |
336 | const Gcalc_scan_iterator *si, |
337 | Gcalc_function::shape_type s_t); |
338 | int add_single_point(const Gcalc_scan_iterator *si); |
339 | poly_border *get_pair_border(poly_border *b1); |
340 | int continue_range(active_thread *t, const Gcalc_heap::Info *p, |
341 | const Gcalc_heap::Info *p_next); |
342 | int continue_i_range(active_thread *t, |
343 | const Gcalc_heap::Info *ii); |
344 | int end_couple(active_thread *t0, active_thread *t1, const Gcalc_heap::Info *p); |
345 | int get_single_result(res_point *res, Gcalc_result_receiver *storage); |
346 | int get_result_thread(res_point *cur, Gcalc_result_receiver *storage, |
347 | int move_upward, res_point *first_poly_node); |
348 | int get_polygon_result(res_point *cur, Gcalc_result_receiver *storage, |
349 | res_point *first_poly_node); |
350 | int get_line_result(res_point *cur, Gcalc_result_receiver *storage); |
351 | |
352 | void free_result(res_point *res); |
353 | }; |
354 | |
355 | #endif /*GCALC_TOOLS_INCLUDED*/ |
356 | |
357 | |