agg_rasterizer_cells_aa.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. //----------------------------------------------------------------------------
  2. // Anti-Grain Geometry - Version 2.4
  3. // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
  4. //
  5. // C# port by: Lars Brubaker
  6. // larsbrubaker@gmail.com
  7. // Copyright (C) 2007
  8. //
  9. // Permission to copy, use, modify, sell and distribute this software
  10. // is granted provided this copyright notice appears in all copies.
  11. // This software is provided "as is" without express or implied
  12. // warranty, and with no claim as to its suitability for any purpose.
  13. //
  14. //----------------------------------------------------------------------------
  15. //
  16. // The author gratefully acknowledges the support of David Turner,
  17. // Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
  18. // library - in producing this work. See http://www.freetype.org for details.
  19. //
  20. //----------------------------------------------------------------------------
  21. // Contact: mcseem@antigrain.com
  22. // mcseemagg@yahoo.com
  23. // http://www.antigrain.com
  24. //----------------------------------------------------------------------------
  25. //
  26. // Adaptation for 32-bit screen coordinates has been sponsored by
  27. // Liberty Technology Systems, Inc., visit http://lib-sys.com
  28. //
  29. // Liberty Technology Systems, Inc. is the provider of
  30. // PostScript and PDF technology for software developers.
  31. //
  32. //----------------------------------------------------------------------------
  33. using poly_subpixel_scale_e = MatterHackers.Agg.Util.poly_subpixel_scale_e;
  34. namespace MatterHackers.Agg
  35. {
  36. //-----------------------------------------------------------------cell_aa
  37. // A pixel cell. There are no constructors defined and it was done
  38. // intentionally in order to avoid extra overhead when allocating an
  39. // array of cells.
  40. public struct PixelCellAa
  41. {
  42. public int x;
  43. public int y;
  44. public int cover;
  45. public int area;
  46. public int left, right;
  47. public void Initial()
  48. {
  49. x = 0x7FFFFFFF;
  50. y = 0x7FFFFFFF;
  51. cover = 0;
  52. area = 0;
  53. left = -1;
  54. right = -1;
  55. }
  56. public void Set(PixelCellAa cellB)
  57. {
  58. x = cellB.x;
  59. y = cellB.y;
  60. cover = cellB.cover;
  61. area = cellB.area;
  62. left = cellB.left;
  63. right = cellB.right;
  64. }
  65. public void Style(PixelCellAa cellB)
  66. {
  67. left = cellB.left;
  68. right = cellB.right;
  69. }
  70. public bool NotEqual(int ex, int ey, PixelCellAa cell)
  71. {
  72. unchecked
  73. {
  74. return ((ex - x) | (ey - y) | (left - cell.left) | (right - cell.right)) != 0;
  75. }
  76. }
  77. };
  78. //-----------------------------------------------------rasterizer_cells_aa
  79. // An internal class that implements the main rasterization algorithm.
  80. // Used in the rasterizer. Should not be used directly.
  81. public sealed class RasterizerCellsAa
  82. {
  83. private int m_num_used_cells;
  84. private VectorPOD<PixelCellAa> m_cells;
  85. private VectorPOD<PixelCellAa> m_sorted_cells;
  86. private VectorPOD<sorted_y> m_sorted_y;
  87. private QuickSortCellAa m_QSorter;
  88. private PixelCellAa m_curr_cell;
  89. private PixelCellAa m_style_cell;
  90. private int m_min_x;
  91. private int m_min_y;
  92. private int m_max_x;
  93. private int m_max_y;
  94. private bool m_sorted;
  95. private enum cell_block_scale_e
  96. {
  97. cell_block_shift = 12,
  98. cell_block_size = 1 << cell_block_shift,
  99. cell_block_mask = cell_block_size - 1,
  100. cell_block_pool = 256,
  101. cell_block_limit = 1024 * cell_block_size
  102. };
  103. private struct sorted_y
  104. {
  105. internal int start;
  106. internal int num;
  107. };
  108. public RasterizerCellsAa()
  109. {
  110. m_QSorter = new QuickSortCellAa();
  111. m_sorted_cells = new VectorPOD<PixelCellAa>();
  112. m_sorted_y = new VectorPOD<sorted_y>();
  113. m_min_x = (0x7FFFFFFF);
  114. m_min_y = (0x7FFFFFFF);
  115. m_max_x = (-0x7FFFFFFF);
  116. m_max_y = (-0x7FFFFFFF);
  117. m_sorted = (false);
  118. m_style_cell.Initial();
  119. m_curr_cell.Initial();
  120. }
  121. public void reset()
  122. {
  123. m_num_used_cells = 0;
  124. m_curr_cell.Initial();
  125. m_style_cell.Initial();
  126. m_sorted = false;
  127. m_min_x = 0x7FFFFFFF;
  128. m_min_y = 0x7FFFFFFF;
  129. m_max_x = -0x7FFFFFFF;
  130. m_max_y = -0x7FFFFFFF;
  131. }
  132. public void style(PixelCellAa style_cell)
  133. {
  134. m_style_cell.Style(style_cell);
  135. }
  136. private enum dx_limit_e { dx_limit = 16384 << Util.poly_subpixel_scale_e.poly_subpixel_shift };
  137. public void line(int x1, int y1, int x2, int y2)
  138. {
  139. int poly_subpixel_shift = (int)Util.poly_subpixel_scale_e.poly_subpixel_shift;
  140. int poly_subpixel_mask = (int)Util.poly_subpixel_scale_e.poly_subpixel_mask;
  141. int poly_subpixel_scale = (int)Util.poly_subpixel_scale_e.poly_subpixel_scale;
  142. int dx = x2 - x1;
  143. if (dx >= (int)dx_limit_e.dx_limit || dx <= -(int)dx_limit_e.dx_limit)
  144. {
  145. int cx = (x1 + x2) >> 1;
  146. int cy = (y1 + y2) >> 1;
  147. line(x1, y1, cx, cy);
  148. line(cx, cy, x2, y2);
  149. }
  150. int dy = y2 - y1;
  151. int ex1 = x1 >> poly_subpixel_shift;
  152. int ex2 = x2 >> poly_subpixel_shift;
  153. int ey1 = y1 >> poly_subpixel_shift;
  154. int ey2 = y2 >> poly_subpixel_shift;
  155. int fy1 = y1 & poly_subpixel_mask;
  156. int fy2 = y2 & poly_subpixel_mask;
  157. int x_from, x_to;
  158. int p, rem, mod, lift, delta, first, incr;
  159. if (ex1 < m_min_x) m_min_x = ex1;
  160. if (ex1 > m_max_x) m_max_x = ex1;
  161. if (ey1 < m_min_y) m_min_y = ey1;
  162. if (ey1 > m_max_y) m_max_y = ey1;
  163. if (ex2 < m_min_x) m_min_x = ex2;
  164. if (ex2 > m_max_x) m_max_x = ex2;
  165. if (ey2 < m_min_y) m_min_y = ey2;
  166. if (ey2 > m_max_y) m_max_y = ey2;
  167. set_curr_cell(ex1, ey1);
  168. //everything is on a single horizontal line
  169. if (ey1 == ey2)
  170. {
  171. render_hline(ey1, x1, fy1, x2, fy2);
  172. return;
  173. }
  174. //Vertical line - we have to calculate start and end cells,
  175. //and then - the common values of the area and coverage for
  176. //all cells of the line. We know exactly there's only one
  177. //cell, so, we don't have to call render_hline().
  178. incr = 1;
  179. if (dx == 0)
  180. {
  181. int ex = x1 >> poly_subpixel_shift;
  182. int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1;
  183. int area;
  184. first = poly_subpixel_scale;
  185. if (dy < 0)
  186. {
  187. first = 0;
  188. incr = -1;
  189. }
  190. x_from = x1;
  191. delta = first - fy1;
  192. m_curr_cell.cover += delta;
  193. m_curr_cell.area += two_fx * delta;
  194. ey1 += incr;
  195. set_curr_cell(ex, ey1);
  196. delta = first + first - poly_subpixel_scale;
  197. area = two_fx * delta;
  198. while (ey1 != ey2)
  199. {
  200. m_curr_cell.cover = delta;
  201. m_curr_cell.area = area;
  202. ey1 += incr;
  203. set_curr_cell(ex, ey1);
  204. }
  205. delta = fy2 - poly_subpixel_scale + first;
  206. m_curr_cell.cover += delta;
  207. m_curr_cell.area += two_fx * delta;
  208. return;
  209. }
  210. //ok, we have to render several hlines
  211. p = (poly_subpixel_scale - fy1) * dx;
  212. first = poly_subpixel_scale;
  213. if (dy < 0)
  214. {
  215. p = fy1 * dx;
  216. first = 0;
  217. incr = -1;
  218. dy = -dy;
  219. }
  220. delta = p / dy;
  221. mod = p % dy;
  222. if (mod < 0)
  223. {
  224. delta--;
  225. mod += dy;
  226. }
  227. x_from = x1 + delta;
  228. render_hline(ey1, x1, fy1, x_from, first);
  229. ey1 += incr;
  230. set_curr_cell(x_from >> poly_subpixel_shift, ey1);
  231. if (ey1 != ey2)
  232. {
  233. p = poly_subpixel_scale * dx;
  234. lift = p / dy;
  235. rem = p % dy;
  236. if (rem < 0)
  237. {
  238. lift--;
  239. rem += dy;
  240. }
  241. mod -= dy;
  242. while (ey1 != ey2)
  243. {
  244. delta = lift;
  245. mod += rem;
  246. if (mod >= 0)
  247. {
  248. mod -= dy;
  249. delta++;
  250. }
  251. x_to = x_from + delta;
  252. render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first);
  253. x_from = x_to;
  254. ey1 += incr;
  255. set_curr_cell(x_from >> poly_subpixel_shift, ey1);
  256. }
  257. }
  258. render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2);
  259. }
  260. public int min_x()
  261. {
  262. return m_min_x;
  263. }
  264. public int min_y()
  265. {
  266. return m_min_y;
  267. }
  268. public int max_x()
  269. {
  270. return m_max_x;
  271. }
  272. public int max_y()
  273. {
  274. return m_max_y;
  275. }
  276. public void sort_cells()
  277. {
  278. if (m_sorted) return; //Perform sort only the first time.
  279. add_curr_cell();
  280. m_curr_cell.x = 0x7FFFFFFF;
  281. m_curr_cell.y = 0x7FFFFFFF;
  282. m_curr_cell.cover = 0;
  283. m_curr_cell.area = 0;
  284. if (m_num_used_cells == 0) return;
  285. // Allocate the array of cell pointers
  286. m_sorted_cells.Allocate(m_num_used_cells);
  287. // Allocate and zero the Y array
  288. m_sorted_y.Allocate((int)(m_max_y - m_min_y + 1));
  289. m_sorted_y.zero();
  290. PixelCellAa[] cells = m_cells.Array;
  291. sorted_y[] sortedYData = m_sorted_y.Array;
  292. PixelCellAa[] sortedCellsData = m_sorted_cells.Array;
  293. // Create the Y-histogram (count the numbers of cells for each Y)
  294. for (int i = 0; i < m_num_used_cells; i++)
  295. {
  296. int Index = cells[i].y - m_min_y;
  297. sortedYData[Index].start++;
  298. }
  299. // Convert the Y-histogram into the array of starting indexes
  300. int start = 0;
  301. int SortedYSize = m_sorted_y.Count;
  302. for (int i = 0; i < SortedYSize; i++)
  303. {
  304. int v = sortedYData[i].start;
  305. sortedYData[i].start = start;
  306. start += v;
  307. }
  308. // Fill the cell pointer array sorted by Y
  309. for (int i = 0; i < m_num_used_cells; i++)
  310. {
  311. int SortedIndex = cells[i].y - m_min_y;
  312. int curr_y_start = sortedYData[SortedIndex].start;
  313. int curr_y_num = sortedYData[SortedIndex].num;
  314. sortedCellsData[curr_y_start + curr_y_num] = cells[i];
  315. ++sortedYData[SortedIndex].num;
  316. }
  317. // Finally arrange the X-arrays
  318. for (int i = 0; i < SortedYSize; i++)
  319. {
  320. if (sortedYData[i].num != 0)
  321. {
  322. m_QSorter.Sort(sortedCellsData, sortedYData[i].start, sortedYData[i].start + sortedYData[i].num - 1);
  323. }
  324. }
  325. m_sorted = true;
  326. }
  327. public int total_cells()
  328. {
  329. return m_num_used_cells;
  330. }
  331. public int scanline_num_cells(int y)
  332. {
  333. return (int)m_sorted_y.data()[y - m_min_y].num;
  334. }
  335. public void scanline_cells(int y, out PixelCellAa[] CellData, out int Offset)
  336. {
  337. CellData = m_sorted_cells.data();
  338. Offset = m_sorted_y[y - m_min_y].start;
  339. }
  340. public bool sorted()
  341. {
  342. return m_sorted;
  343. }
  344. private void set_curr_cell(int x, int y)
  345. {
  346. if (m_curr_cell.NotEqual(x, y, m_style_cell))
  347. {
  348. add_curr_cell();
  349. m_curr_cell.Style(m_style_cell);
  350. m_curr_cell.x = x;
  351. m_curr_cell.y = y;
  352. m_curr_cell.cover = 0;
  353. m_curr_cell.area = 0;
  354. }
  355. }
  356. private void add_curr_cell()
  357. {
  358. if ((m_curr_cell.area | m_curr_cell.cover) != 0)
  359. {
  360. if (m_num_used_cells >= (int)cell_block_scale_e.cell_block_limit)
  361. {
  362. return;
  363. }
  364. allocate_cells_if_required();
  365. m_cells.data()[m_num_used_cells].Set(m_curr_cell);
  366. m_num_used_cells++;
  367. #if false
  368. if(m_num_used_cells == 281)
  369. {
  370. int a = 12;
  371. }
  372. DebugFile.Print(m_num_used_cells.ToString()
  373. + ". x=" + m_curr_cell.m_x.ToString()
  374. + " y=" + m_curr_cell.m_y.ToString()
  375. + " area=" + m_curr_cell.m_area.ToString()
  376. + " cover=" + m_curr_cell.m_cover.ToString()
  377. + "\n");
  378. #endif
  379. }
  380. }
  381. private void allocate_cells_if_required()
  382. {
  383. if (m_cells == null || (m_num_used_cells + 1) >= m_cells.Capacity())
  384. {
  385. if (m_num_used_cells >= (int)cell_block_scale_e.cell_block_limit)
  386. {
  387. return;
  388. }
  389. int new_num_allocated_cells = m_num_used_cells + (int)cell_block_scale_e.cell_block_size;
  390. VectorPOD<PixelCellAa> new_cells = new VectorPOD<PixelCellAa>(new_num_allocated_cells);
  391. if (m_cells != null)
  392. {
  393. new_cells.CopyFrom(m_cells);
  394. }
  395. m_cells = new_cells;
  396. }
  397. }
  398. private void render_hline(int ey, int x1, int y1, int x2, int y2)
  399. {
  400. int ex1 = x1 >> (int)poly_subpixel_scale_e.poly_subpixel_shift;
  401. int ex2 = x2 >> (int)poly_subpixel_scale_e.poly_subpixel_shift;
  402. int fx1 = x1 & (int)poly_subpixel_scale_e.poly_subpixel_mask;
  403. int fx2 = x2 & (int)poly_subpixel_scale_e.poly_subpixel_mask;
  404. int delta, p, first, dx;
  405. int incr, lift, mod, rem;
  406. //trivial case. Happens often
  407. if (y1 == y2)
  408. {
  409. set_curr_cell(ex2, ey);
  410. return;
  411. }
  412. //everything is located in a single cell. That is easy!
  413. if (ex1 == ex2)
  414. {
  415. delta = y2 - y1;
  416. m_curr_cell.cover += delta;
  417. m_curr_cell.area += (fx1 + fx2) * delta;
  418. return;
  419. }
  420. //ok, we'll have to render a run of adjacent cells on the same hline...
  421. p = ((int)poly_subpixel_scale_e.poly_subpixel_scale - fx1) * (y2 - y1);
  422. first = (int)poly_subpixel_scale_e.poly_subpixel_scale;
  423. incr = 1;
  424. dx = x2 - x1;
  425. if (dx < 0)
  426. {
  427. p = fx1 * (y2 - y1);
  428. first = 0;
  429. incr = -1;
  430. dx = -dx;
  431. }
  432. delta = p / dx;
  433. mod = p % dx;
  434. if (mod < 0)
  435. {
  436. delta--;
  437. mod += dx;
  438. }
  439. m_curr_cell.cover += delta;
  440. m_curr_cell.area += (fx1 + first) * delta;
  441. ex1 += incr;
  442. set_curr_cell(ex1, ey);
  443. y1 += delta;
  444. if (ex1 != ex2)
  445. {
  446. p = (int)poly_subpixel_scale_e.poly_subpixel_scale * (y2 - y1 + delta);
  447. lift = p / dx;
  448. rem = p % dx;
  449. if (rem < 0)
  450. {
  451. lift--;
  452. rem += dx;
  453. }
  454. mod -= dx;
  455. while (ex1 != ex2)
  456. {
  457. delta = lift;
  458. mod += rem;
  459. if (mod >= 0)
  460. {
  461. mod -= dx;
  462. delta++;
  463. }
  464. m_curr_cell.cover += delta;
  465. m_curr_cell.area += (int)poly_subpixel_scale_e.poly_subpixel_scale * delta;
  466. y1 += delta;
  467. ex1 += incr;
  468. set_curr_cell(ex1, ey);
  469. }
  470. }
  471. delta = y2 - y1;
  472. m_curr_cell.cover += delta;
  473. m_curr_cell.area += (fx2 + (int)poly_subpixel_scale_e.poly_subpixel_scale - first) * delta;
  474. }
  475. private static void swap_cells(PixelCellAa a, PixelCellAa b)
  476. {
  477. PixelCellAa temp = a;
  478. a = b;
  479. b = temp;
  480. }
  481. private enum qsort { threshold = 9 };
  482. }
  483. //------------------------------------------------------scanline_hit_test
  484. public class scanline_hit_test : IScanlineCache
  485. {
  486. private int m_x;
  487. private bool m_hit;
  488. public scanline_hit_test(int x)
  489. {
  490. m_x = x;
  491. m_hit = false;
  492. }
  493. public void ResetSpans()
  494. {
  495. }
  496. public void finalize(int nothing)
  497. {
  498. }
  499. public void add_cell(int x, int nothing)
  500. {
  501. if (m_x == x) m_hit = true;
  502. }
  503. public void add_span(int x, int len, int nothing)
  504. {
  505. if (m_x >= x && m_x < x + len) m_hit = true;
  506. }
  507. public int num_spans()
  508. {
  509. return 1;
  510. }
  511. public bool hit()
  512. {
  513. return m_hit;
  514. }
  515. public void reset(int min_x, int max_x)
  516. {
  517. throw new System.NotImplementedException();
  518. }
  519. public ScanlineSpan begin()
  520. {
  521. throw new System.NotImplementedException();
  522. }
  523. public ScanlineSpan GetNextScanlineSpan()
  524. {
  525. throw new System.NotImplementedException();
  526. }
  527. public int y()
  528. {
  529. throw new System.NotImplementedException();
  530. }
  531. public byte[] GetCovers()
  532. {
  533. throw new System.NotImplementedException();
  534. }
  535. }
  536. }