polygon.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*!
  2. \file lib/pngdriver/polygon.c
  3. \brief GRASS png display driver - draw polygon
  4. (C) 2003-2014 by Per Henrik Johansen and the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Per Henrik Johansen (original contributor)
  8. \author Glynn Clements
  9. */
  10. #include <stdlib.h>
  11. #include <math.h>
  12. #include <grass/gis.h>
  13. #include "path.h"
  14. #include "pngdriver.h"
  15. static int cmp_double(const void *aa, const void *bb)
  16. {
  17. const double *a = aa;
  18. const double *b = bb;
  19. return
  20. *a > *b ? 1 :
  21. *a < *b ? -1 :
  22. 0;
  23. }
  24. static void fill(double x0, double x1, double y)
  25. {
  26. int yi = (int) floor(y);
  27. int xi0 = (int) floor(x0 + 0.5);
  28. int xi1 = (int) floor(x1 + 0.5);
  29. unsigned int *p;
  30. int x;
  31. if (yi >= png.clip_bot || yi < png.clip_top)
  32. return;
  33. if (xi0 > png.clip_rite)
  34. return;
  35. if (xi1 < png.clip_left)
  36. return;
  37. if (xi0 < png.clip_left)
  38. xi0 = png.clip_left;
  39. if (xi1 > png.clip_rite)
  40. xi1 = png.clip_rite;
  41. p = &png.grid[yi * png.width + xi0];
  42. for (x = xi0; x < xi1; x++)
  43. *p++ = png.current_color;
  44. }
  45. static void line(const struct vertex *p, int n, double y)
  46. {
  47. static double *xs;
  48. static int max_x;
  49. int num_x = 0;
  50. int i;
  51. for (i = 1; i < n; i++) {
  52. const struct vertex *p0 = &p[i - 1];
  53. const struct vertex *p1 = &p[i];
  54. const struct vertex *tmp;
  55. double x;
  56. if (p0->y == p1->y)
  57. continue;
  58. if (p0->y > p1->y)
  59. tmp = p0, p0 = p1, p1 = tmp;
  60. if (p0->y > y)
  61. continue;
  62. if (p1->y <= y)
  63. continue;
  64. x = p1->x * (y - p0->y) + p0->x * (p1->y - y);
  65. x /= p1->y - p0->y;
  66. if (num_x >= max_x) {
  67. max_x += 20;
  68. xs = G_realloc(xs, max_x * sizeof(double));
  69. }
  70. xs[num_x++] = x;
  71. }
  72. qsort(xs, num_x, sizeof(double), cmp_double);
  73. for (i = 0; i + 1 < num_x; i += 2)
  74. fill(xs[i], xs[i + 1], y);
  75. }
  76. static void poly(const struct vertex *p, int n)
  77. {
  78. double y0, y1, y;
  79. int i;
  80. if (n < 3)
  81. return;
  82. y0 = y1 = p[0].y;
  83. for (i = 1; i < n; i++) {
  84. if (y0 > p[i].y)
  85. y0 = p[i].y;
  86. if (y1 < p[i].y)
  87. y1 = p[i].y;
  88. }
  89. if (y0 > png.clip_bot || y1 < png.clip_top)
  90. return;
  91. if (y0 < png.clip_top)
  92. y0 = png.clip_top;
  93. if (y1 > png.clip_bot)
  94. y1 = png.clip_bot;
  95. for (y = floor(y0 + 0.5) + 0.5; y < y1; y++)
  96. line(p, n, y);
  97. }
  98. /*!
  99. \brief Draw polygon
  100. */
  101. void png_polygon(struct path *p)
  102. {
  103. if (p->vertices[p->count - 1].mode != P_CLOSE)
  104. path_close(p);
  105. poly(p->vertices, p->count);
  106. png.modified = 1;
  107. }