mi_plycon.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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_gc.h"
  23. #include "mi_api.h"
  24. #include "mi_scanfill.h"
  25. /* forward references */
  26. static int getPolyYBounds (const miPoint *pts, int n, int *by, int *ty);
  27. /*
  28. * Written by Brian Kelleher; Dec. 1985.
  29. * Hacked by Robert S. Maier, 1998-99.
  30. *
  31. * Fill a convex polygon (if the polygon is not convex then the result is
  32. * undefined). The algorithm is to order the edges from smallest y to
  33. * largest y, by partitioning the array into a left edge list and a right
  34. * edge list. The algorithm used to traverse each edge is an extension of
  35. * Bresenham's midpoint line algorithm, with y as the major axis.
  36. *
  37. * All painting goes through the low-level MI_PAINT_SPANS() macro.
  38. *
  39. * See mi_plygen.c for miFillGeneralPoly(), a slower routine that can fill
  40. * general polygons (i.e. polygons that may be non-convex or
  41. * self-intersecting). */
  42. /* ARGS: pGC = unused */
  43. void
  44. miFillConvexPoly (miPaintedSet *paintedSet, const miGC *pGC, int count, const miPoint *ptsIn)
  45. /* count = num of points, ptsIn = the points */
  46. {
  47. int xl = 0, xr = 0; /* x vals of left and right edges */
  48. int dl = 0, dr = 0; /* decision variables */
  49. int ml = 0, m1l = 0; /* left edge slope and slope+1 */
  50. int mr = 0, m1r = 0; /* right edge slope and slope+1 */
  51. int incr1l = 0, incr2l = 0; /* left edge error increments */
  52. int incr1r = 0, incr2r = 0; /* right edge error increments */
  53. int dy; /* delta y */
  54. int y; /* current scanline */
  55. int left, right; /* indices to first endpoints */
  56. int i; /* loop counter */
  57. int nextleft, nextright; /* indices to second endpoints */
  58. miPoint *ptsOut, *FirstPoint; /* output buffer */
  59. unsigned int *width, *FirstWidth; /* output buffer */
  60. int imin; /* index of smallest vertex (in y) */
  61. int ymin; /* y-extents of polygon */
  62. int ymax;
  63. /*
  64. * find leftx, bottomy, rightx, topy, and the index
  65. * of bottomy. Also translate the points.
  66. */
  67. imin = getPolyYBounds(ptsIn, count, &ymin, &ymax);
  68. dy = ymax - ymin + 1;
  69. if ((count < 3) || (dy < 0))
  70. return;
  71. ptsOut = FirstPoint = (miPoint *)mi_xmalloc(sizeof(miPoint) * dy);
  72. width = FirstWidth = (unsigned int *)mi_xmalloc(sizeof(unsigned int) * dy);
  73. nextleft = nextright = imin;
  74. y = ptsIn[nextleft].y;
  75. /*
  76. * loop through all edges of the polygon
  77. */
  78. do {
  79. /*
  80. * add a left edge if we need to
  81. */
  82. if (ptsIn[nextleft].y == y)
  83. {
  84. left = nextleft;
  85. /*
  86. * find the next edge, considering the end
  87. * conditions of the array.
  88. */
  89. nextleft++;
  90. if (nextleft >= count)
  91. nextleft = 0;
  92. /*
  93. * now compute all of the random information
  94. * needed to run the iterative algorithm.
  95. */
  96. BRESINITPGON(ptsIn[nextleft].y-ptsIn[left].y,
  97. ptsIn[left].x,ptsIn[nextleft].x,
  98. xl, dl, ml, m1l, incr1l, incr2l);
  99. }
  100. /*
  101. * add a right edge if we need to
  102. */
  103. if (ptsIn[nextright].y == y)
  104. {
  105. right = nextright;
  106. /*
  107. * find the next edge, considering the end
  108. * conditions of the array.
  109. */
  110. nextright--;
  111. if (nextright < 0)
  112. nextright = count-1;
  113. /*
  114. * now compute all of the random information
  115. * needed to run the iterative algorithm.
  116. */
  117. BRESINITPGON(ptsIn[nextright].y-ptsIn[right].y,
  118. ptsIn[right].x,ptsIn[nextright].x,
  119. xr, dr, mr, m1r, incr1r, incr2r);
  120. }
  121. /*
  122. * generate scans to fill while we still have
  123. * a right edge as well as a left edge.
  124. */
  125. i = IMIN(ptsIn[nextleft].y, ptsIn[nextright].y) - y;
  126. /* in case we're called with non-convex polygon */
  127. if(i < 0)
  128. {
  129. free (FirstWidth);
  130. free (FirstPoint);
  131. return;
  132. }
  133. while (i-- > 0)
  134. {
  135. ptsOut->y = y;
  136. /*
  137. * reverse the edges if necessary
  138. */
  139. if (xl < xr)
  140. {
  141. *(width++) = (unsigned int)(xr - xl);
  142. (ptsOut++)->x = xl;
  143. }
  144. else
  145. {
  146. *(width++) = (unsigned int)(xl - xr);
  147. (ptsOut++)->x = xr;
  148. }
  149. y++;
  150. /* increment down the edges */
  151. BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
  152. BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
  153. }
  154. } while (y != ymax);
  155. /*
  156. * Finally, paint the <remaining> spans
  157. */
  158. MI_PAINT_SPANS(paintedSet, pGC->pixels[1], ptsOut - FirstPoint, FirstPoint, FirstWidth)
  159. }
  160. /*
  161. * Find the index of the point with the smallest y.
  162. */
  163. static int
  164. getPolyYBounds (const miPoint *pts, int n, int *by, int *ty)
  165. {
  166. const miPoint *ptsStart = pts;
  167. const miPoint *ptMin;
  168. int ymin, ymax;
  169. ptMin = pts;
  170. ymin = ymax = (pts++)->y;
  171. while (--n > 0)
  172. {
  173. if (pts->y < ymin)
  174. {
  175. ptMin = pts;
  176. ymin = pts->y;
  177. }
  178. if(pts->y > ymax)
  179. ymax = pts->y;
  180. pts++;
  181. }
  182. *by = ymin;
  183. *ty = ymax;
  184. return (ptMin - ptsStart);
  185. }