My Project
|
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