agg_rasterizer_outline_aa.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. using MatterHackers.Agg.VertexSource;
  2. //----------------------------------------------------------------------------
  3. // Anti-Grain Geometry - Version 2.4
  4. // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
  5. //
  6. // Permission to copy, use, modify, sell and distribute this software
  7. // is granted provided this copyright notice appears in all copies.
  8. // This software is provided "as is" without express or implied
  9. // warranty, and with no claim as to its suitability for any purpose.
  10. //
  11. //----------------------------------------------------------------------------
  12. // Contact: mcseem@antigrain.com
  13. // mcseemagg@yahoo.com
  14. // http://www.antigrain.com
  15. //----------------------------------------------------------------------------
  16. using System;
  17. namespace MatterHackers.Agg
  18. {
  19. //-----------------------------------------------------------line_aa_vertex
  20. // Vertex (x, y) with the distance to the next one. The last vertex has
  21. // the distance between the last and the first points
  22. public struct line_aa_vertex
  23. {
  24. public int x;
  25. public int y;
  26. public int len;
  27. public line_aa_vertex(int x_, int y_)
  28. {
  29. x = (x_);
  30. y = (y_);
  31. len = (0);
  32. }
  33. public bool Compare(line_aa_vertex val)
  34. {
  35. double dx = val.x - x;
  36. double dy = val.y - y;
  37. return (len = Util.uround(Math.Sqrt(dx * dx + dy * dy))) >
  38. (LineAABasics.line_subpixel_scale + LineAABasics.line_subpixel_scale / 2);
  39. }
  40. };
  41. public class line_aa_vertex_sequence : VectorPOD<line_aa_vertex>
  42. {
  43. public override void add(line_aa_vertex val)
  44. {
  45. if (base.Count > 1)
  46. {
  47. if (!Array[base.Count - 2].Compare(Array[base.Count - 1]))
  48. {
  49. base.RemoveLast();
  50. }
  51. }
  52. base.add(val);
  53. }
  54. public void modify_last(line_aa_vertex val)
  55. {
  56. base.RemoveLast();
  57. add(val);
  58. }
  59. public void close(bool closed)
  60. {
  61. while (base.Count > 1)
  62. {
  63. if (Array[base.Count - 2].Compare(Array[base.Count - 1])) break;
  64. line_aa_vertex t = this[base.Count - 1];
  65. base.RemoveLast();
  66. modify_last(t);
  67. }
  68. if (closed)
  69. {
  70. while (base.Count > 1)
  71. {
  72. if (Array[base.Count - 1].Compare(Array[0])) break;
  73. base.RemoveLast();
  74. }
  75. }
  76. }
  77. internal line_aa_vertex prev(int idx)
  78. {
  79. return this[(idx + currentSize - 1) % currentSize];
  80. }
  81. internal line_aa_vertex curr(int idx)
  82. {
  83. return this[idx];
  84. }
  85. internal line_aa_vertex next(int idx)
  86. {
  87. return this[(idx + 1) % currentSize];
  88. }
  89. }
  90. //=======================================================rasterizer_outline_aa
  91. public class rasterizer_outline_aa
  92. {
  93. private LineRenderer m_ren;
  94. private line_aa_vertex_sequence m_src_vertices = new line_aa_vertex_sequence();
  95. private outline_aa_join_e m_line_join;
  96. private bool m_round_cap;
  97. private int m_start_x;
  98. private int m_start_y;
  99. public enum outline_aa_join_e
  100. {
  101. outline_no_join, //-----outline_no_join
  102. outline_miter_join, //-----outline_miter_join
  103. outline_round_join, //-----outline_round_join
  104. outline_miter_accurate_join //-----outline_accurate_join
  105. };
  106. public bool cmp_dist_start(int d)
  107. {
  108. return d > 0;
  109. }
  110. public bool cmp_dist_end(int d)
  111. {
  112. return d <= 0;
  113. }
  114. private struct draw_vars
  115. {
  116. public int idx;
  117. public int x1, y1, x2, y2;
  118. public line_parameters curr, next;
  119. public int lcurr, lnext;
  120. public int xb1, yb1, xb2, yb2;
  121. public int flags;
  122. };
  123. private void draw(ref draw_vars dv, int start, int end)
  124. {
  125. int i;
  126. for (i = start; i < end; i++)
  127. {
  128. if (m_line_join == outline_aa_join_e.outline_round_join)
  129. {
  130. dv.xb1 = dv.curr.x1 + (dv.curr.y2 - dv.curr.y1);
  131. dv.yb1 = dv.curr.y1 - (dv.curr.x2 - dv.curr.x1);
  132. dv.xb2 = dv.curr.x2 + (dv.curr.y2 - dv.curr.y1);
  133. dv.yb2 = dv.curr.y2 - (dv.curr.x2 - dv.curr.x1);
  134. }
  135. switch (dv.flags)
  136. {
  137. case 0: m_ren.line3(dv.curr, dv.xb1, dv.yb1, dv.xb2, dv.yb2); break;
  138. case 1: m_ren.line2(dv.curr, dv.xb2, dv.yb2); break;
  139. case 2: m_ren.line1(dv.curr, dv.xb1, dv.yb1); break;
  140. case 3: m_ren.line0(dv.curr); break;
  141. }
  142. if (m_line_join == outline_aa_join_e.outline_round_join && (dv.flags & 2) == 0)
  143. {
  144. m_ren.pie(dv.curr.x2, dv.curr.y2,
  145. dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
  146. dv.curr.y2 - (dv.curr.x2 - dv.curr.x1),
  147. dv.curr.x2 + (dv.next.y2 - dv.next.y1),
  148. dv.curr.y2 - (dv.next.x2 - dv.next.x1));
  149. }
  150. dv.x1 = dv.x2;
  151. dv.y1 = dv.y2;
  152. dv.lcurr = dv.lnext;
  153. dv.lnext = m_src_vertices[dv.idx].len;
  154. ++dv.idx;
  155. if (dv.idx >= m_src_vertices.Count) dv.idx = 0;
  156. dv.x2 = m_src_vertices[dv.idx].x;
  157. dv.y2 = m_src_vertices[dv.idx].y;
  158. dv.curr = dv.next;
  159. dv.next = new line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
  160. dv.xb1 = dv.xb2;
  161. dv.yb1 = dv.yb2;
  162. switch (m_line_join)
  163. {
  164. case outline_aa_join_e.outline_no_join:
  165. dv.flags = 3;
  166. break;
  167. case outline_aa_join_e.outline_miter_join:
  168. dv.flags >>= 1;
  169. dv.flags |= (dv.curr.diagonal_quadrant() ==
  170. dv.next.diagonal_quadrant() ? 1 : 0);
  171. if ((dv.flags & 2) == 0)
  172. {
  173. LineAABasics.bisectrix(dv.curr, dv.next, out dv.xb2, out dv.yb2);
  174. }
  175. break;
  176. case outline_aa_join_e.outline_round_join:
  177. dv.flags >>= 1;
  178. dv.flags |= (((dv.curr.diagonal_quadrant() ==
  179. dv.next.diagonal_quadrant()) ? 1 : 0) << 1);
  180. break;
  181. case outline_aa_join_e.outline_miter_accurate_join:
  182. dv.flags = 0;
  183. LineAABasics.bisectrix(dv.curr, dv.next, out dv.xb2, out dv.yb2);
  184. break;
  185. }
  186. }
  187. }
  188. public rasterizer_outline_aa(LineRenderer ren)
  189. {
  190. m_ren = ren;
  191. m_line_join = (OutlineRenderer.accurate_join_only() ?
  192. outline_aa_join_e.outline_miter_accurate_join :
  193. outline_aa_join_e.outline_round_join);
  194. m_round_cap = (false);
  195. m_start_x = (0);
  196. m_start_y = (0);
  197. }
  198. public void attach(LineRenderer ren)
  199. {
  200. m_ren = ren;
  201. }
  202. public void line_join(outline_aa_join_e join)
  203. {
  204. m_line_join = OutlineRenderer.accurate_join_only() ?
  205. outline_aa_join_e.outline_miter_accurate_join :
  206. join;
  207. }
  208. public outline_aa_join_e line_join()
  209. {
  210. return m_line_join;
  211. }
  212. public void round_cap(bool v)
  213. {
  214. m_round_cap = v;
  215. }
  216. public bool round_cap()
  217. {
  218. return m_round_cap;
  219. }
  220. public void move_to(int x, int y)
  221. {
  222. m_src_vertices.modify_last(new line_aa_vertex(m_start_x = x, m_start_y = y));
  223. }
  224. public void line_to(int x, int y)
  225. {
  226. m_src_vertices.add(new line_aa_vertex(x, y));
  227. }
  228. public void move_to_d(double x, double y)
  229. {
  230. move_to(line_coord_sat.conv(x), line_coord_sat.conv(y));
  231. }
  232. public void line_to_d(double x, double y)
  233. {
  234. line_to(line_coord_sat.conv(x), line_coord_sat.conv(y));
  235. }
  236. public void render(bool close_polygon)
  237. {
  238. m_src_vertices.close(close_polygon);
  239. draw_vars dv = new draw_vars();
  240. line_aa_vertex v;
  241. int x1;
  242. int y1;
  243. int x2;
  244. int y2;
  245. int lprev;
  246. if (close_polygon)
  247. {
  248. if (m_src_vertices.Count >= 3)
  249. {
  250. dv.idx = 2;
  251. v = m_src_vertices[m_src_vertices.Count - 1];
  252. x1 = v.x;
  253. y1 = v.y;
  254. lprev = v.len;
  255. v = m_src_vertices[0];
  256. x2 = v.x;
  257. y2 = v.y;
  258. dv.lcurr = v.len;
  259. line_parameters prev = new line_parameters(x1, y1, x2, y2, lprev);
  260. v = m_src_vertices[1];
  261. dv.x1 = v.x;
  262. dv.y1 = v.y;
  263. dv.lnext = v.len;
  264. dv.curr = new line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
  265. v = m_src_vertices[dv.idx];
  266. dv.x2 = v.x;
  267. dv.y2 = v.y;
  268. dv.next = new line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
  269. dv.xb1 = 0;
  270. dv.yb1 = 0;
  271. dv.xb2 = 0;
  272. dv.yb2 = 0;
  273. switch (m_line_join)
  274. {
  275. case outline_aa_join_e.outline_no_join:
  276. dv.flags = 3;
  277. break;
  278. case outline_aa_join_e.outline_miter_join:
  279. case outline_aa_join_e.outline_round_join:
  280. dv.flags =
  281. (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant() ? 1 : 0) |
  282. ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant() ? 1 : 0) << 1);
  283. break;
  284. case outline_aa_join_e.outline_miter_accurate_join:
  285. dv.flags = 0;
  286. break;
  287. }
  288. if ((dv.flags & 1) == 0 && m_line_join != outline_aa_join_e.outline_round_join)
  289. {
  290. LineAABasics.bisectrix(prev, dv.curr, out dv.xb1, out dv.yb1);
  291. }
  292. if ((dv.flags & 2) == 0 && m_line_join != outline_aa_join_e.outline_round_join)
  293. {
  294. LineAABasics.bisectrix(dv.curr, dv.next, out dv.xb2, out dv.yb2);
  295. }
  296. draw(ref dv, 0, m_src_vertices.Count);
  297. }
  298. }
  299. else
  300. {
  301. switch (m_src_vertices.Count)
  302. {
  303. case 0:
  304. case 1:
  305. break;
  306. case 2:
  307. {
  308. v = m_src_vertices[0];
  309. x1 = v.x;
  310. y1 = v.y;
  311. lprev = v.len;
  312. v = m_src_vertices[1];
  313. x2 = v.x;
  314. y2 = v.y;
  315. line_parameters lp = new line_parameters(x1, y1, x2, y2, lprev);
  316. if (m_round_cap)
  317. {
  318. m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
  319. }
  320. m_ren.line3(lp,
  321. x1 + (y2 - y1),
  322. y1 - (x2 - x1),
  323. x2 + (y2 - y1),
  324. y2 - (x2 - x1));
  325. if (m_round_cap)
  326. {
  327. m_ren.semidot(cmp_dist_end, x2, y2, x2 + (y2 - y1), y2 - (x2 - x1));
  328. }
  329. }
  330. break;
  331. case 3:
  332. {
  333. int x3, y3;
  334. int lnext;
  335. v = m_src_vertices[0];
  336. x1 = v.x;
  337. y1 = v.y;
  338. lprev = v.len;
  339. v = m_src_vertices[1];
  340. x2 = v.x;
  341. y2 = v.y;
  342. lnext = v.len;
  343. v = m_src_vertices[2];
  344. x3 = v.x;
  345. y3 = v.y;
  346. line_parameters lp1 = new line_parameters(x1, y1, x2, y2, lprev);
  347. line_parameters lp2 = new line_parameters(x2, y2, x3, y3, lnext);
  348. if (m_round_cap)
  349. {
  350. m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
  351. }
  352. if (m_line_join == outline_aa_join_e.outline_round_join)
  353. {
  354. m_ren.line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
  355. x2 + (y2 - y1), y2 - (x2 - x1));
  356. m_ren.pie(x2, y2, x2 + (y2 - y1), y2 - (x2 - x1),
  357. x2 + (y3 - y2), y2 - (x3 - x2));
  358. m_ren.line3(lp2, x2 + (y3 - y2), y2 - (x3 - x2),
  359. x3 + (y3 - y2), y3 - (x3 - x2));
  360. }
  361. else
  362. {
  363. LineAABasics.bisectrix(lp1, lp2, out dv.xb1, out dv.yb1);
  364. m_ren.line3(lp1, x1 + (y2 - y1), y1 - (x2 - x1),
  365. dv.xb1, dv.yb1);
  366. m_ren.line3(lp2, dv.xb1, dv.yb1,
  367. x3 + (y3 - y2), y3 - (x3 - x2));
  368. }
  369. if (m_round_cap)
  370. {
  371. m_ren.semidot(cmp_dist_end, x3, y3, x3 + (y3 - y2), y3 - (x3 - x2));
  372. }
  373. }
  374. break;
  375. default:
  376. {
  377. dv.idx = 3;
  378. v = m_src_vertices[0];
  379. x1 = v.x;
  380. y1 = v.y;
  381. lprev = v.len;
  382. v = m_src_vertices[1];
  383. x2 = v.x;
  384. y2 = v.y;
  385. dv.lcurr = v.len;
  386. line_parameters prev = new line_parameters(x1, y1, x2, y2, lprev);
  387. v = m_src_vertices[2];
  388. dv.x1 = v.x;
  389. dv.y1 = v.y;
  390. dv.lnext = v.len;
  391. dv.curr = new line_parameters(x2, y2, dv.x1, dv.y1, dv.lcurr);
  392. v = m_src_vertices[dv.idx];
  393. dv.x2 = v.x;
  394. dv.y2 = v.y;
  395. dv.next = new line_parameters(dv.x1, dv.y1, dv.x2, dv.y2, dv.lnext);
  396. dv.xb1 = 0;
  397. dv.yb1 = 0;
  398. dv.xb2 = 0;
  399. dv.yb2 = 0;
  400. switch (m_line_join)
  401. {
  402. case outline_aa_join_e.outline_no_join:
  403. dv.flags = 3;
  404. break;
  405. case outline_aa_join_e.outline_miter_join:
  406. case outline_aa_join_e.outline_round_join:
  407. dv.flags =
  408. (prev.diagonal_quadrant() == dv.curr.diagonal_quadrant() ? 1 : 0) |
  409. ((dv.curr.diagonal_quadrant() == dv.next.diagonal_quadrant() ? 1 : 0) << 1);
  410. break;
  411. case outline_aa_join_e.outline_miter_accurate_join:
  412. dv.flags = 0;
  413. break;
  414. }
  415. if (m_round_cap)
  416. {
  417. m_ren.semidot(cmp_dist_start, x1, y1, x1 + (y2 - y1), y1 - (x2 - x1));
  418. }
  419. if ((dv.flags & 1) == 0)
  420. {
  421. if (m_line_join == outline_aa_join_e.outline_round_join)
  422. {
  423. m_ren.line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
  424. x2 + (y2 - y1), y2 - (x2 - x1));
  425. m_ren.pie(prev.x2, prev.y2,
  426. x2 + (y2 - y1), y2 - (x2 - x1),
  427. dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
  428. dv.curr.y1 - (dv.curr.x2 - dv.curr.x1));
  429. }
  430. else
  431. {
  432. LineAABasics.bisectrix(prev, dv.curr, out dv.xb1, out dv.yb1);
  433. m_ren.line3(prev, x1 + (y2 - y1), y1 - (x2 - x1),
  434. dv.xb1, dv.yb1);
  435. }
  436. }
  437. else
  438. {
  439. m_ren.line1(prev,
  440. x1 + (y2 - y1),
  441. y1 - (x2 - x1));
  442. }
  443. if ((dv.flags & 2) == 0 && m_line_join != outline_aa_join_e.outline_round_join)
  444. {
  445. LineAABasics.bisectrix(dv.curr, dv.next, out dv.xb2, out dv.yb2);
  446. }
  447. draw(ref dv, 1, m_src_vertices.Count - 2);
  448. if ((dv.flags & 1) == 0)
  449. {
  450. if (m_line_join == outline_aa_join_e.outline_round_join)
  451. {
  452. m_ren.line3(dv.curr,
  453. dv.curr.x1 + (dv.curr.y2 - dv.curr.y1),
  454. dv.curr.y1 - (dv.curr.x2 - dv.curr.x1),
  455. dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
  456. dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
  457. }
  458. else
  459. {
  460. m_ren.line3(dv.curr, dv.xb1, dv.yb1,
  461. dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
  462. dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
  463. }
  464. }
  465. else
  466. {
  467. m_ren.line2(dv.curr,
  468. dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
  469. dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
  470. }
  471. if (m_round_cap)
  472. {
  473. m_ren.semidot(cmp_dist_end, dv.curr.x2, dv.curr.y2,
  474. dv.curr.x2 + (dv.curr.y2 - dv.curr.y1),
  475. dv.curr.y2 - (dv.curr.x2 - dv.curr.x1));
  476. }
  477. }
  478. break;
  479. }
  480. }
  481. m_src_vertices.Clear();
  482. }
  483. public void add_vertex(double x, double y, ShapePath.FlagsAndCommand cmd)
  484. {
  485. if (ShapePath.is_move_to(cmd))
  486. {
  487. render(false);
  488. move_to_d(x, y);
  489. }
  490. else
  491. {
  492. if (ShapePath.is_end_poly(cmd))
  493. {
  494. render(ShapePath.is_closed(cmd));
  495. if (ShapePath.is_closed(cmd))
  496. {
  497. move_to(m_start_x, m_start_y);
  498. }
  499. }
  500. else
  501. {
  502. line_to_d(x, y);
  503. }
  504. }
  505. }
  506. public void add_path(IVertexSource vs)
  507. {
  508. add_path(vs, 0);
  509. }
  510. public void add_path(IVertexSource vs, int path_id)
  511. {
  512. double x;
  513. double y;
  514. ShapePath.FlagsAndCommand cmd;
  515. vs.rewind(path_id);
  516. //int index = 0;
  517. //int start = 851;
  518. //int num = 5;
  519. while (!ShapePath.is_stop(cmd = vs.vertex(out x, out y)))
  520. {
  521. //index++;
  522. //if (index == 0
  523. // || (index > start && index < start + num))
  524. add_vertex(x, y, cmd);
  525. }
  526. render(false);
  527. }
  528. public void RenderAllPaths(IVertexSource vs,
  529. Color[] colors,
  530. int[] path_id,
  531. int num_paths)
  532. {
  533. for (int i = 0; i < num_paths; i++)
  534. {
  535. m_ren.color(colors[i]);
  536. add_path(vs, path_id[i]);
  537. }
  538. }
  539. /* // for debugging only
  540. public void render_path_index(IVertexSource vs,
  541. RGBA_Bytes[] colors,
  542. int[] path_id,
  543. int pathIndex)
  544. {
  545. m_ren.color(colors[pathIndex]);
  546. add_path(vs, path_id[pathIndex]);
  547. }
  548. */
  549. };
  550. }