agg_conv_gpc.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. //----------------------------------------------------------------------------
  2. // Anti-Grain Geometry - Version 2.4
  3. // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
  4. //
  5. // Permission to copy, use, modify, sell and distribute this software
  6. // is granted provided this copyright notice appears in all copies.
  7. // This software is provided "as is" without express or implied
  8. // warranty, and with no claim as to its suitability for any purpose.
  9. //
  10. //----------------------------------------------------------------------------
  11. // Contact: mcseem@antigrain.com
  12. // mcseemagg@yahoo.com
  13. // http://www.antigrain.com
  14. //----------------------------------------------------------------------------
  15. //
  16. // General Polygon Clipper based on the GPC library by Alan Murta
  17. // Union, Intersection, XOR, A-B, B-A
  18. // Contact the author if you intend to use it in commercial applications!
  19. // http://www.cs.man.ac.uk/aig/staff/alan/software/
  20. // Alan Murta (email: gpc@cs.man.ac.uk)
  21. //
  22. //----------------------------------------------------------------------------
  23. #ifndef AGG_CONV_GPC_INCLUDED
  24. #define AGG_CONV_GPC_INCLUDED
  25. #include <math.h>
  26. #include "agg_basics.h"
  27. #include "agg_array.h"
  28. extern "C"
  29. {
  30. #include "gpc.h"
  31. }
  32. namespace agg
  33. {
  34. enum gpc_op_e
  35. {
  36. gpc_or,
  37. gpc_and,
  38. gpc_xor,
  39. gpc_a_minus_b,
  40. gpc_b_minus_a
  41. };
  42. //================================================================conv_gpc
  43. template<class VSA, class VSB> class conv_gpc
  44. {
  45. enum status
  46. {
  47. status_move_to,
  48. status_line_to,
  49. status_stop
  50. };
  51. struct contour_header_type
  52. {
  53. int num_vertices;
  54. int hole_flag;
  55. gpc_vertex* vertices;
  56. };
  57. typedef pod_bvector<gpc_vertex, 8> vertex_array_type;
  58. typedef pod_bvector<contour_header_type, 6> contour_header_array_type;
  59. public:
  60. typedef VSA source_a_type;
  61. typedef VSB source_b_type;
  62. typedef conv_gpc<source_a_type, source_b_type> self_type;
  63. ~conv_gpc()
  64. {
  65. free_gpc_data();
  66. }
  67. conv_gpc(source_a_type& a, source_b_type& b, gpc_op_e op = gpc_or) :
  68. m_src_a(&a),
  69. m_src_b(&b),
  70. m_status(status_move_to),
  71. m_vertex(-1),
  72. m_contour(-1),
  73. m_operation(op)
  74. {
  75. memset(&m_poly_a, 0, sizeof(m_poly_a));
  76. memset(&m_poly_b, 0, sizeof(m_poly_b));
  77. memset(&m_result, 0, sizeof(m_result));
  78. }
  79. void attach1(VSA& source) { m_src_a = &source; }
  80. void attach2(VSB& source) { m_src_b = &source; }
  81. void operation(gpc_op_e v) { m_operation = v; }
  82. // Vertex Source Interface
  83. void rewind(unsigned path_id);
  84. unsigned vertex(double* x, double* y);
  85. private:
  86. conv_gpc(const conv_gpc<VSA, VSB>&);
  87. const conv_gpc<VSA, VSB>& operator = (const conv_gpc<VSA, VSB>&);
  88. //--------------------------------------------------------------------
  89. void free_polygon(gpc_polygon& p);
  90. void free_result();
  91. void free_gpc_data();
  92. void start_contour();
  93. void add_vertex(double x, double y);
  94. void end_contour(unsigned orientation);
  95. void make_polygon(gpc_polygon& p);
  96. void start_extracting();
  97. bool next_contour();
  98. bool next_vertex(double* x, double* y);
  99. //--------------------------------------------------------------------
  100. template<class VS> void add(VS& src, gpc_polygon& p)
  101. {
  102. unsigned cmd;
  103. double x, y;
  104. double start_x = 0.0;
  105. double start_y = 0.0;
  106. bool line_to = false;
  107. unsigned orientation = 0;
  108. m_contour_accumulator.remove_all();
  109. while(!is_stop(cmd = src.vertex(&x, &y)))
  110. {
  111. if(is_vertex(cmd))
  112. {
  113. if(is_move_to(cmd))
  114. {
  115. if(line_to)
  116. {
  117. end_contour(orientation);
  118. orientation = 0;
  119. }
  120. start_contour();
  121. start_x = x;
  122. start_y = y;
  123. }
  124. add_vertex(x, y);
  125. line_to = true;
  126. }
  127. else
  128. {
  129. if(is_end_poly(cmd))
  130. {
  131. orientation = get_orientation(cmd);
  132. if(line_to && is_closed(cmd))
  133. {
  134. add_vertex(start_x, start_y);
  135. }
  136. }
  137. }
  138. }
  139. if(line_to)
  140. {
  141. end_contour(orientation);
  142. }
  143. make_polygon(p);
  144. }
  145. private:
  146. //--------------------------------------------------------------------
  147. source_a_type* m_src_a;
  148. source_b_type* m_src_b;
  149. status m_status;
  150. int m_vertex;
  151. int m_contour;
  152. gpc_op_e m_operation;
  153. vertex_array_type m_vertex_accumulator;
  154. contour_header_array_type m_contour_accumulator;
  155. gpc_polygon m_poly_a;
  156. gpc_polygon m_poly_b;
  157. gpc_polygon m_result;
  158. };
  159. //------------------------------------------------------------------------
  160. template<class VSA, class VSB>
  161. void conv_gpc<VSA, VSB>::free_polygon(gpc_polygon& p)
  162. {
  163. int i;
  164. for(i = 0; i < p.num_contours; i++)
  165. {
  166. pod_allocator<gpc_vertex>::deallocate(p.contour[i].vertex,
  167. p.contour[i].num_vertices);
  168. }
  169. pod_allocator<gpc_vertex_list>::deallocate(p.contour, p.num_contours);
  170. memset(&p, 0, sizeof(gpc_polygon));
  171. }
  172. //------------------------------------------------------------------------
  173. template<class VSA, class VSB>
  174. void conv_gpc<VSA, VSB>::free_result()
  175. {
  176. if(m_result.contour)
  177. {
  178. gpc_free_polygon(&m_result);
  179. }
  180. memset(&m_result, 0, sizeof(m_result));
  181. }
  182. //------------------------------------------------------------------------
  183. template<class VSA, class VSB>
  184. void conv_gpc<VSA, VSB>::free_gpc_data()
  185. {
  186. free_polygon(m_poly_a);
  187. free_polygon(m_poly_b);
  188. free_result();
  189. }
  190. //------------------------------------------------------------------------
  191. template<class VSA, class VSB>
  192. void conv_gpc<VSA, VSB>::start_contour()
  193. {
  194. contour_header_type h;
  195. memset(&h, 0, sizeof(h));
  196. m_contour_accumulator.add(h);
  197. m_vertex_accumulator.remove_all();
  198. }
  199. //------------------------------------------------------------------------
  200. template<class VSA, class VSB>
  201. inline void conv_gpc<VSA, VSB>::add_vertex(double x, double y)
  202. {
  203. gpc_vertex v;
  204. v.x = x;
  205. v.y = y;
  206. m_vertex_accumulator.add(v);
  207. }
  208. //------------------------------------------------------------------------
  209. template<class VSA, class VSB>
  210. void conv_gpc<VSA, VSB>::end_contour(unsigned orientation)
  211. {
  212. if(m_contour_accumulator.size())
  213. {
  214. if(m_vertex_accumulator.size() > 2)
  215. {
  216. contour_header_type& h =
  217. m_contour_accumulator[m_contour_accumulator.size() - 1];
  218. h.num_vertices = m_vertex_accumulator.size();
  219. h.hole_flag = 0;
  220. // TO DO: Clarify the "holes"
  221. //if(is_cw(orientation)) h.hole_flag = 1;
  222. h.vertices = pod_allocator<gpc_vertex>::allocate(h.num_vertices);
  223. gpc_vertex* d = h.vertices;
  224. int i;
  225. for(i = 0; i < h.num_vertices; i++)
  226. {
  227. const gpc_vertex& s = m_vertex_accumulator[i];
  228. d->x = s.x;
  229. d->y = s.y;
  230. ++d;
  231. }
  232. }
  233. else
  234. {
  235. m_vertex_accumulator.remove_last();
  236. }
  237. }
  238. }
  239. //------------------------------------------------------------------------
  240. template<class VSA, class VSB>
  241. void conv_gpc<VSA, VSB>::make_polygon(gpc_polygon& p)
  242. {
  243. free_polygon(p);
  244. if(m_contour_accumulator.size())
  245. {
  246. p.num_contours = m_contour_accumulator.size();
  247. p.hole = 0;
  248. p.contour = pod_allocator<gpc_vertex_list>::allocate(p.num_contours);
  249. int i;
  250. gpc_vertex_list* pv = p.contour;
  251. for(i = 0; i < p.num_contours; i++)
  252. {
  253. const contour_header_type& h = m_contour_accumulator[i];
  254. pv->num_vertices = h.num_vertices;
  255. pv->vertex = h.vertices;
  256. ++pv;
  257. }
  258. }
  259. }
  260. //------------------------------------------------------------------------
  261. template<class VSA, class VSB>
  262. void conv_gpc<VSA, VSB>::start_extracting()
  263. {
  264. m_status = status_move_to;
  265. m_contour = -1;
  266. m_vertex = -1;
  267. }
  268. //------------------------------------------------------------------------
  269. template<class VSA, class VSB>
  270. bool conv_gpc<VSA, VSB>::next_contour()
  271. {
  272. if(++m_contour < m_result.num_contours)
  273. {
  274. m_vertex = -1;
  275. return true;
  276. }
  277. return false;
  278. }
  279. //------------------------------------------------------------------------
  280. template<class VSA, class VSB>
  281. inline bool conv_gpc<VSA, VSB>::next_vertex(double* x, double* y)
  282. {
  283. const gpc_vertex_list& vlist = m_result.contour[m_contour];
  284. if(++m_vertex < vlist.num_vertices)
  285. {
  286. const gpc_vertex& v = vlist.vertex[m_vertex];
  287. *x = v.x;
  288. *y = v.y;
  289. return true;
  290. }
  291. return false;
  292. }
  293. //------------------------------------------------------------------------
  294. template<class VSA, class VSB>
  295. void conv_gpc<VSA, VSB>::rewind(unsigned path_id)
  296. {
  297. free_result();
  298. m_src_a->rewind(path_id);
  299. m_src_b->rewind(path_id);
  300. add(*m_src_a, m_poly_a);
  301. add(*m_src_b, m_poly_b);
  302. switch(m_operation)
  303. {
  304. case gpc_or:
  305. gpc_polygon_clip(GPC_UNION,
  306. &m_poly_a,
  307. &m_poly_b,
  308. &m_result);
  309. break;
  310. case gpc_and:
  311. gpc_polygon_clip(GPC_INT,
  312. &m_poly_a,
  313. &m_poly_b,
  314. &m_result);
  315. break;
  316. case gpc_xor:
  317. gpc_polygon_clip(GPC_XOR,
  318. &m_poly_a,
  319. &m_poly_b,
  320. &m_result);
  321. break;
  322. case gpc_a_minus_b:
  323. gpc_polygon_clip(GPC_DIFF,
  324. &m_poly_a,
  325. &m_poly_b,
  326. &m_result);
  327. break;
  328. case gpc_b_minus_a:
  329. gpc_polygon_clip(GPC_DIFF,
  330. &m_poly_b,
  331. &m_poly_a,
  332. &m_result);
  333. break;
  334. }
  335. start_extracting();
  336. }
  337. //------------------------------------------------------------------------
  338. template<class VSA, class VSB>
  339. unsigned conv_gpc<VSA, VSB>::vertex(double* x, double* y)
  340. {
  341. if(m_status == status_move_to)
  342. {
  343. if(next_contour())
  344. {
  345. if(next_vertex(x, y))
  346. {
  347. m_status = status_line_to;
  348. return path_cmd_move_to;
  349. }
  350. m_status = status_stop;
  351. return path_cmd_end_poly | path_flags_close;
  352. }
  353. }
  354. else
  355. {
  356. if(next_vertex(x, y))
  357. {
  358. return path_cmd_line_to;
  359. }
  360. else
  361. {
  362. m_status = status_move_to;
  363. }
  364. return path_cmd_end_poly | path_flags_close;
  365. }
  366. return path_cmd_stop;
  367. }
  368. }
  369. #endif