mi_plyutil.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /* This file is part of the GNU libxmi package.
  2. Copyright (C) 1985, 1986, 1987, 1988, 1989, X Consortium. For an
  3. associated permission notice, see the accompanying file README-X.
  4. GNU enhancements Copyright (C) 1998, 1999, 2000, 2005, Free Software
  5. Foundation, Inc.
  6. The GNU libxmi package is free software. You may redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software foundation; either version 2, or (at your
  9. option) any later version.
  10. The GNU libxmi package is distributed in the hope that it will be
  11. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with the GNU plotutils package; see the file COPYING. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  17. Boston, MA 02110-1301, USA. */
  18. #include "sys-defines.h"
  19. #include "extern.h"
  20. #include "xmi.h"
  21. #include "mi_spans.h"
  22. #include "mi_api.h"
  23. #include "mi_scanfill.h"
  24. #include "mi_ply.h"
  25. /*
  26. * Written by Brian Kelleher; Oct. 1985
  27. *
  28. * This module contains all of the utility functions
  29. * needed to scan-convert a polygon. The driver subroutine,
  30. * miFillGeneralPoly(), is in mi_plygen.c.
  31. */
  32. /*
  33. * InsertEdgeInET
  34. *
  35. * Insert the given edge into the edge table.
  36. * First we must find the correct bucket in the
  37. * Edge table, then find the right slot in the
  38. * bucket. Finally, we can insert it.
  39. *
  40. */
  41. static void
  42. miInsertEdgeInET (EdgeTable *ET, EdgeTableEntry *ETE, int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
  43. {
  44. EdgeTableEntry *start, *prev;
  45. ScanLineList *pSLL, *pPrevSLL;
  46. ScanLineListBlock *tmpSLLBlock;
  47. /*
  48. * find the right bucket to put the edge into
  49. */
  50. pPrevSLL = &ET->scanlines;
  51. pSLL = pPrevSLL->next;
  52. while (pSLL && (pSLL->scanline < scanline))
  53. {
  54. pPrevSLL = pSLL;
  55. pSLL = pSLL->next;
  56. }
  57. /*
  58. * reassign pSLL (pointer to ScanLineList) if necessary
  59. */
  60. if ((!pSLL) || (pSLL->scanline > scanline))
  61. {
  62. if (*iSLLBlock > SLLSPERBLOCK-1)
  63. {
  64. tmpSLLBlock =
  65. (ScanLineListBlock *)mi_xmalloc(sizeof(ScanLineListBlock));
  66. (*SLLBlock)->next = tmpSLLBlock;
  67. tmpSLLBlock->next = (ScanLineListBlock *)NULL;
  68. *SLLBlock = tmpSLLBlock;
  69. *iSLLBlock = 0;
  70. }
  71. pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
  72. pSLL->next = pPrevSLL->next;
  73. pSLL->edgelist = (EdgeTableEntry *)NULL;
  74. pPrevSLL->next = pSLL;
  75. }
  76. pSLL->scanline = scanline;
  77. /*
  78. * now insert the edge in the right bucket
  79. */
  80. prev = (EdgeTableEntry *)NULL;
  81. start = pSLL->edgelist;
  82. while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
  83. {
  84. prev = start;
  85. start = start->next;
  86. }
  87. ETE->next = start;
  88. if (prev)
  89. prev->next = ETE;
  90. else
  91. pSLL->edgelist = ETE;
  92. }
  93. /*
  94. * CreateEdgeTable
  95. *
  96. * This routine creates the edge table for
  97. * scan converting polygons.
  98. * The Edge Table (ET) looks like:
  99. *
  100. * EdgeTable
  101. * --------
  102. * | ymax | ScanLineLists
  103. * |scanline|-->------------>-------------->...
  104. * -------- |scanline| |scanline|
  105. * |edgelist| |edgelist|
  106. * --------- ---------
  107. * | |
  108. * | |
  109. * V V
  110. * list of ETEs list of ETEs
  111. *
  112. * where ETE is an EdgeTableEntry data structure,
  113. * and there is one ScanLineList per scanline at
  114. * which an edge is initially entered.
  115. *
  116. */
  117. void
  118. miCreateETandAET(int count, const miPoint *pts, EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
  119. {
  120. const miPoint *top, *bottom;
  121. const miPoint *PrevPt, *CurrPt;
  122. int iSLLBlock = 0;
  123. int dy;
  124. if (count < 2)
  125. return;
  126. /*
  127. * initialize the Active Edge Table
  128. */
  129. AET->next = (EdgeTableEntry *)NULL;
  130. AET->back = (EdgeTableEntry *)NULL;
  131. AET->nextWETE = (EdgeTableEntry *)NULL;
  132. AET->bres.minor_axis = INT_MIN;
  133. /*
  134. * initialize the Edge Table.
  135. */
  136. ET->scanlines.next = (ScanLineList *)NULL;
  137. ET->ymax = INT_MIN;
  138. ET->ymin = INT_MAX;
  139. pSLLBlock->next = (ScanLineListBlock *)NULL;
  140. PrevPt = &pts[count-1];
  141. /*
  142. * for each vertex in the array of points.
  143. * In this loop we are dealing with two vertices at
  144. * a time -- these make up one edge of the polygon.
  145. */
  146. while (count--)
  147. {
  148. CurrPt = pts++;
  149. /*
  150. * find out which point is above and which is below.
  151. */
  152. if (PrevPt->y > CurrPt->y)
  153. {
  154. bottom = PrevPt, top = CurrPt;
  155. pETEs->ClockWise = false;
  156. }
  157. else
  158. {
  159. bottom = CurrPt, top = PrevPt;
  160. pETEs->ClockWise = true;
  161. }
  162. /*
  163. * don't add horizontal edges to the Edge table.
  164. */
  165. if (bottom->y != top->y)
  166. {
  167. pETEs->ymax = bottom->y-1; /* -1 so we don't get last scanline */
  168. /*
  169. * initialize integer edge algorithm
  170. */
  171. dy = bottom->y - top->y;
  172. BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
  173. miInsertEdgeInET (ET, pETEs, top->y, &pSLLBlock, &iSLLBlock);
  174. ET->ymax = IMAX(ET->ymax, PrevPt->y);
  175. ET->ymin = IMIN(ET->ymin, PrevPt->y);
  176. pETEs++;
  177. }
  178. PrevPt = CurrPt;
  179. }
  180. }
  181. /*
  182. * loadAET
  183. *
  184. * This routine moves EdgeTableEntries from the
  185. * EdgeTable into the Active Edge Table,
  186. * leaving them sorted by smaller x coordinate.
  187. *
  188. */
  189. void
  190. miloadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
  191. {
  192. EdgeTableEntry *pPrevAET;
  193. EdgeTableEntry *tmp;
  194. pPrevAET = AET;
  195. AET = AET->next;
  196. while (ETEs)
  197. {
  198. while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
  199. {
  200. pPrevAET = AET;
  201. AET = AET->next;
  202. }
  203. tmp = ETEs->next;
  204. ETEs->next = AET;
  205. if (AET)
  206. AET->back = ETEs;
  207. ETEs->back = pPrevAET;
  208. pPrevAET->next = ETEs;
  209. pPrevAET = ETEs;
  210. ETEs = tmp;
  211. }
  212. }
  213. /*
  214. * computeWAET
  215. *
  216. * This routine links the AET by the
  217. * nextWETE (winding EdgeTableEntry) link for
  218. * use by the winding number rule. The final
  219. * Active Edge Table (AET) might look something
  220. * like:
  221. *
  222. * AET
  223. * ---------- --------- ---------
  224. * |ymax | |ymax | |ymax |
  225. * | ... | |... | |... |
  226. * |next |->|next |->|next |->...
  227. * |nextWETE| |nextWETE| |nextWETE|
  228. * --------- --------- ^--------
  229. * | | |
  230. * V-------------------> V---> ...
  231. *
  232. */
  233. void
  234. micomputeWAET(EdgeTableEntry *AET)
  235. {
  236. EdgeTableEntry *pWETE;
  237. int inside = 1;
  238. int isInside = 0;
  239. AET->nextWETE = (EdgeTableEntry *)NULL;
  240. pWETE = AET;
  241. AET = AET->next;
  242. while (AET)
  243. {
  244. if (AET->ClockWise)
  245. isInside++;
  246. else
  247. isInside--;
  248. if ((!inside && !isInside) ||
  249. ( inside && isInside))
  250. {
  251. pWETE->nextWETE = AET;
  252. pWETE = AET;
  253. inside = !inside;
  254. }
  255. AET = AET->next;
  256. }
  257. pWETE->nextWETE = (EdgeTableEntry *)NULL;
  258. }
  259. /*
  260. * InsertionSort
  261. *
  262. * Just a simple insertion sort using
  263. * pointers and back pointers to sort the Active
  264. * Edge Table.
  265. *
  266. */
  267. bool
  268. miInsertionSort(EdgeTableEntry *AET)
  269. {
  270. EdgeTableEntry *pETEchase;
  271. EdgeTableEntry *pETEinsert;
  272. EdgeTableEntry *pETEchaseBackTMP;
  273. bool changed = false;
  274. AET = AET->next;
  275. while (AET)
  276. {
  277. pETEinsert = AET;
  278. pETEchase = AET;
  279. while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
  280. pETEchase = pETEchase->back;
  281. AET = AET->next;
  282. if (pETEchase != pETEinsert)
  283. {
  284. pETEchaseBackTMP = pETEchase->back;
  285. pETEinsert->back->next = AET;
  286. if (AET)
  287. AET->back = pETEinsert->back;
  288. pETEinsert->next = pETEchase;
  289. pETEchase->back->next = pETEinsert;
  290. pETEchase->back = pETEinsert;
  291. pETEinsert->back = pETEchaseBackTMP;
  292. changed = true;
  293. }
  294. }
  295. return changed;
  296. }
  297. /*
  298. * Clean up our act.
  299. */
  300. void
  301. miFreeStorage(ScanLineListBlock *pSLLBlock)
  302. {
  303. ScanLineListBlock *tmpSLLBlock;
  304. while (pSLLBlock)
  305. {
  306. tmpSLLBlock = pSLLBlock->next;
  307. free(pSLLBlock);
  308. pSLLBlock = tmpSLLBlock;
  309. }
  310. }