/*! \file lib/pngdriver/polygon.c \brief GRASS png display driver - draw polygon (C) 2003-2014 by Per Henrik Johansen and the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. \author Per Henrik Johansen (original contributor) \author Glynn Clements */ #include #include #include #include "path.h" #include "pngdriver.h" static int cmp_double(const void *aa, const void *bb) { const double *a = aa; const double *b = bb; return *a > *b ? 1 : *a < *b ? -1 : 0; } static void fill(double x0, double x1, double y) { int yi = (int) floor(y); int xi0 = (int) floor(x0 + 0.5); int xi1 = (int) floor(x1 + 0.5); unsigned int *p; int x; if (yi >= png.clip_bot || yi < png.clip_top) return; if (xi0 > png.clip_rite) return; if (xi1 < png.clip_left) return; if (xi0 < png.clip_left) xi0 = png.clip_left; if (xi1 > png.clip_rite) xi1 = png.clip_rite; p = &png.grid[yi * png.width + xi0]; for (x = xi0; x < xi1; x++) *p++ = png.current_color; } static void line(const struct vertex *p, int n, double y) { static double *xs; static int max_x; int num_x = 0; int i; for (i = 1; i < n; i++) { const struct vertex *p0 = &p[i - 1]; const struct vertex *p1 = &p[i]; const struct vertex *tmp; double x; if (p0->y == p1->y) continue; if (p0->y > p1->y) tmp = p0, p0 = p1, p1 = tmp; if (p0->y > y) continue; if (p1->y <= y) continue; x = p1->x * (y - p0->y) + p0->x * (p1->y - y); x /= p1->y - p0->y; if (num_x >= max_x) { max_x += 20; xs = G_realloc(xs, max_x * sizeof(double)); } xs[num_x++] = x; } qsort(xs, num_x, sizeof(double), cmp_double); for (i = 0; i + 1 < num_x; i += 2) fill(xs[i], xs[i + 1], y); } static void poly(const struct vertex *p, int n) { double y0, y1, y; int i; if (n < 3) return; y0 = y1 = p[0].y; for (i = 1; i < n; i++) { if (y0 > p[i].y) y0 = p[i].y; if (y1 < p[i].y) y1 = p[i].y; } if (y0 > png.clip_bot || y1 < png.clip_top) return; if (y0 < png.clip_top) y0 = png.clip_top; if (y1 > png.clip_bot) y1 = png.clip_bot; for (y = floor(y0 + 0.5) + 0.5; y < y1; y++) line(p, n, y); } /*! \brief Draw polygon */ void png_polygon(struct path *p) { if (p->vertices[p->count - 1].mode != P_CLOSE) path_close(p); poly(p->vertices, p->count); png.modified = 1; }