You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
10 KiB

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