mi_fplycon.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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_fply.h"
  24. /* forward references */
  25. static int GetFPolyYBounds (const SppPoint *pts, int n, double yFtrans, int *by, int *ty);
  26. /*
  27. * Written by Todd Newman; April 1987.
  28. * Hacked by Robert S. Maier, 1998-1999.
  29. *
  30. * Fill a convex polygon, with SPP (subpixel placement) of vertices. If
  31. * the given polygon is not convex, then the result is undefined. All
  32. * painting goes through the low-level MI_PAINT_SPANS() macro.
  33. *
  34. * In libxmi, this is used to draw polygonal line caps and line joins for
  35. * poly-arcs. See mi_arc.c.
  36. *
  37. * The algorithm is to order the edges from smallest y to largest y, by
  38. * partitioning the array into a left edge list and a right edge list. The
  39. * algorithm used to traverse each edge is the digital differencing
  40. * analyzer line algorithm, with y as the major axis. There's some funny
  41. * linear interpolation involved because of the subpixel postioning. */
  42. /* ARGS: count = # points, ptsIn = points,
  43. xTrans,yTrans = translation for each point,
  44. xFtrans,yFtrans = translation before conversion, which provides a
  45. mechanism to match rounding errors with any
  46. shape that meets the polygon exactly. */
  47. void
  48. miFillSppPoly (miPaintedSet *paintedSet, miPixel pixel, int count, const SppPoint *ptsIn, int xTrans, int yTrans, double xFtrans, double yFtrans)
  49. {
  50. double xl = 0.0, /* x vals of left and right edges */
  51. xr = 0.0,
  52. ml = 0.0, /* left edge slope */
  53. mr = 0.0, /* right edge slope */
  54. dy, /* delta y */
  55. i; /* loop counter */
  56. int y, /* current scanline */
  57. j,
  58. imin, /* index of vertex with smallest y */
  59. ymin, /* y-extents of polygon */
  60. ymax;
  61. int left, right, /* indices to first endpoints */
  62. nextleft,
  63. nextright; /* indices to second endpoints */
  64. int *Marked; /* set if this vertex has been used */
  65. unsigned int *width,
  66. *FirstWidth; /* output buffer */
  67. miPoint *ptsOut,
  68. *FirstPoint; /* output buffer */
  69. imin = GetFPolyYBounds (ptsIn, count, yFtrans, &ymin, &ymax);
  70. y = ymax - ymin + 1;
  71. if ((count < 3) || (y <= 0))
  72. return;
  73. ptsOut = FirstPoint = (miPoint *)mi_xmalloc(sizeof(miPoint) * y);
  74. width = FirstWidth = (unsigned int *)mi_xmalloc(sizeof(unsigned int) * y);
  75. Marked = (int *) mi_xmalloc(sizeof(int) * count);
  76. for (j = 0; j < count; j++)
  77. Marked[j] = 0;
  78. nextleft = nextright = imin;
  79. Marked[imin] = -1;
  80. y = ICEIL(ptsIn[nextleft].y + yFtrans);
  81. /*
  82. * loop through all edges of the polygon
  83. */
  84. do
  85. {
  86. /* add a left edge if we need to */
  87. if ((y > (ptsIn[nextleft].y + yFtrans) ||
  88. ISEQUAL(y, ptsIn[nextleft].y + yFtrans))
  89. && Marked[nextleft] != 1)
  90. {
  91. Marked[nextleft]++;
  92. left = nextleft++;
  93. /* find the next edge, considering the end conditions */
  94. if (nextleft >= count)
  95. nextleft = 0;
  96. /* now compute the starting point and slope */
  97. dy = ptsIn[nextleft].y - ptsIn[left].y;
  98. if (dy != 0.0)
  99. {
  100. ml = (ptsIn[nextleft].x - ptsIn[left].x) / dy;
  101. dy = y - (ptsIn[left].y + yFtrans);
  102. xl = (ptsIn[left].x + xFtrans) + ml * DMAX(dy, 0);
  103. }
  104. }
  105. /* add a right edge if we need to */
  106. if ((y > ptsIn[nextright].y + yFtrans)
  107. ||
  108. (ISEQUAL(y, ptsIn[nextright].y + yFtrans)
  109. && Marked[nextright] != 1))
  110. {
  111. Marked[nextright]++;
  112. right = nextright--;
  113. /* find the next edge, considering the end conditions */
  114. if (nextright < 0)
  115. nextright = count - 1;
  116. /* now compute the starting point and slope */
  117. dy = ptsIn[nextright].y - ptsIn[right].y;
  118. if (dy != 0.0)
  119. {
  120. mr = (ptsIn[nextright].x - ptsIn[right].x) / dy;
  121. dy = y - (ptsIn[right].y + yFtrans);
  122. xr = (ptsIn[right].x + xFtrans) + mr * DMAX(dy, 0);
  123. }
  124. }
  125. /*
  126. * generate scans to fill while we still have
  127. * a right edge as well as a left edge.
  128. */
  129. i = (DMIN(ptsIn[nextleft].y, ptsIn[nextright].y) + yFtrans) - y;
  130. if (i < EPSILON)
  131. {
  132. if(Marked[nextleft] && Marked[nextright])
  133. {
  134. /* Arrgh, we're trapped! (no more points)
  135. * Out, we've got to get out of here before this decadence saps
  136. * our will completely! */
  137. break;
  138. }
  139. continue;
  140. }
  141. else
  142. {
  143. j = (int) i;
  144. if (!j)
  145. j++;
  146. }
  147. while (j > 0)
  148. {
  149. int cxl, cxr;
  150. ptsOut->y = (y) + yTrans;
  151. cxl = ICEIL(xl);
  152. cxr = ICEIL(xr);
  153. /* reverse the edges if necessary */
  154. if (xl < xr)
  155. {
  156. *(width++) = (unsigned int)(cxr - cxl);
  157. (ptsOut++)->x = cxl + xTrans;
  158. }
  159. else
  160. {
  161. *(width++) = (unsigned int)(cxl - cxr);
  162. (ptsOut++)->x = cxr + xTrans;
  163. }
  164. y++;
  165. /* increment down the edges */
  166. xl += ml;
  167. xr += mr;
  168. j--;
  169. }
  170. } while (y <= ymax);
  171. free (Marked);
  172. /* paint the spans (to miPaintedSet, or if NULL, to the canvas) */
  173. MI_PAINT_SPANS(paintedSet, pixel, ptsOut - FirstPoint, FirstPoint, FirstWidth)
  174. }
  175. /* Find the index of the point with the smallest y. Also return the
  176. smallest and largest y. */
  177. static int
  178. GetFPolyYBounds (const SppPoint *pts, int n, double yFtrans, int *by, int *ty)
  179. {
  180. const SppPoint *ptsStart = pts;
  181. const SppPoint *ptMin;
  182. double ymin, ymax;
  183. ptMin = pts;
  184. ymin = ymax = (pts++)->y;
  185. while (--n > 0)
  186. {
  187. if (pts->y < ymin)
  188. {
  189. ptMin = pts;
  190. ymin = pts->y;
  191. }
  192. if(pts->y > ymax)
  193. ymax = pts->y;
  194. pts++;
  195. }
  196. *by = ICEIL(ymin + yFtrans);
  197. *ty = ICEIL(ymax + yFtrans - 1);
  198. return (ptMin - ptsStart);
  199. }