diff options
Diffstat (limited to '')
-rw-r--r-- | common.h | 21 | ||||
-rw-r--r-- | rtgrpblib_draw_linear_bezier.c | 118 |
2 files changed, 119 insertions, 20 deletions
@@ -159,4 +159,25 @@ intolerant_eq(double a, double b) }\ } while (0) +# if 0 +static void +print_raster(const RASTER *r) { + size_t y, x; + fprintf(stderr, "\nOutline (area)\n"); + for (y = 0; y < r->height; y++) { + for (x = 0; x < r->width; x++) + fprintf(stderr, r->cells[y * r->width + x].cell_coverage ? "%+.4lf " : " 0 ", + r->cells[y * r->width + x].cell_coverage); + printf("\n"); + } + fprintf(stderr, "\nOutline (shadow)\n"); + for (y = 0; y < r->height; y++) { + for (x = 0; x < r->width; x++) + fprintf(stderr, r->cells[y * r->width + x].opposite_coverage ? "%+.4lf " : " 0 ", + r->cells[y * r->width + x].opposite_coverage); + printf("\n"); + } +} +# endif + #endif diff --git a/rtgrpblib_draw_linear_bezier.c b/rtgrpblib_draw_linear_bezier.c index ba8dc48..8cefcb1 100644 --- a/rtgrpblib_draw_linear_bezier.c +++ b/rtgrpblib_draw_linear_bezier.c @@ -7,19 +7,21 @@ void rtgrpblib_draw_linear_bezier(RASTER *restrict raster, double x1, double y1, double x2, double y2) { double w, h, dx, dy, x, y; - int xdir, ydir; if (raster->draftness <= 0) { draw_linear_bezier_reference(raster, x1, y1, x2, y2); return; } - dx = x2 - x1; - dy = y2 - y1; - xdir = SIGNUM(dx); - ydir = SIGNUM(dy); +#define CALC_SLOPE()\ + do {\ + dx = x2 - x1;\ + dy = y2 - y1;\ + } while (0) - if (!ydir) { + CALC_SLOPE(); + + if (!dy) { /* For horizontal lines, it is enough that we have the * corners mapped onto the raster, which we must have * since a glyph cannot just contain a line, but outlines: @@ -32,23 +34,27 @@ rtgrpblib_draw_linear_bezier(RASTER *restrict raster, double x1, double y1, doub /* We cut of everything above and below the raster, * as these do not contribute to the result */ h = (double)raster->height; - if (y1 < 0 && y2 < 0) + if (y1 <= 0 && y2 <= 0) return; if (y1 >= h && y2 >= h) return; if (y1 < 0 && y2 >= 0) { x1 = x1 + (0 - y1) * dx / dy; y1 = 0; + CALC_SLOPE(); } else if (y2 < 0 && y1 >= 0) { x2 = x1 + (0 - y1) * dx / dy; y2 = 0; + CALC_SLOPE(); } - if (y1 < h && y2 >= h) { + if (y1 <= h && y2 > h) { x2 = x1 + (h - y1) * dx / dy; y2 = h; - } else if (y2 < h && y1 >= h) { + CALC_SLOPE(); + } else if (y2 <= h && y1 > h) { x1 = x1 + (h - y1) * dx / dy; y1 = h; + CALC_SLOPE(); } /* Dealing with the left and the right section @@ -61,60 +67,132 @@ rtgrpblib_draw_linear_bezier(RASTER *restrict raster, double x1, double y1, doub * edge, or rather their show on the edges are * used. */ w = (double)raster->width; - if (x1 <= 0 && x2 <= 0) { - draw_vertical_line(raster, 0, y1, y2, ydir); + if (x1 < 0 && x2 < 0) { + draw_vertical_line(raster, 0, y1, y2, SIGNUM(dy)); return; } if (x1 >= w && x2 >= w) { - draw_vertical_line_opposite_only(raster, raster->width - 1, y1, y2, ydir); + draw_vertical_line_opposite_only(raster, raster->width - 1, y1, y2, SIGNUM(dy)); return; } if (x1 < 0 && x2 >= 0) { y = y1 + (0 - x1) * dy / dx; x = 0; - draw_vertical_line(raster, 0, y1, y, ydir); + draw_vertical_line(raster, 0, y1, y, SIGNUM(y - y1)); x1 = x; y1 = y; + CALC_SLOPE(); } else if (x2 < 0 && x1 >= 0) { y = y1 + (0 - x1) * dy / dx; x = 0; - draw_vertical_line(raster, 0, y, y2, ydir); + draw_vertical_line(raster, 0, y, y2, SIGNUM(y2 - y)); x2 = x; y2 = y; + CALC_SLOPE(); } if (x1 < w && x2 >= w) { y = y1 + (w - x1) * dy / dx; x = w; - draw_vertical_line_opposite_only(raster, raster->width - 1, y, y2, ydir); + draw_vertical_line_opposite_only(raster, raster->width - 1, y, y2, SIGNUM(y2 - y)); x2 = x; y2 = y; + CALC_SLOPE(); } else if (x2 < w && x1 >= w) { y = y1 + (w - x1) * dy / dx; x = w; - draw_vertical_line_opposite_only(raster, raster->width - 1, y1, y, ydir); + draw_vertical_line_opposite_only(raster, raster->width - 1, y1, y, SIGNUM(y - y1)); x1 = x; y1 = y; + CALC_SLOPE(); } /* Now we can finally draw the part of the * line that is inside the raster */ - if (!xdir) { + if (!dx) { /* Optimisation for vertical lines. It also serves * to illustrate how the algorithm is designed. */ - draw_vertical_line(raster, x1, y1, y2, ydir); + draw_vertical_line(raster, x1, y1, y2, SIGNUM(dy)); } else { - draw_diagonal_line(raster, x1, y1, x2, y2, dx, dy, xdir, ydir); + draw_diagonal_line(raster, x1, y1, x2, y2, dx, dy, SIGNUM(dx), SIGNUM(dy)); } + +#undef CALC_SLOPE } #else +static RASTER *raster; +static RASTER *refraster; + + +static void +check_draw_linear_bezier(double x1, double y1, double x2, double y2) +{ + size_t i; + alarm(5); + rtgrpblib_draw_linear_bezier(raster, x1, y1, x2, y2); + alarm(5); + draw_linear_bezier_reference(refraster, x1, y1, x2, y2); + alarm(0); + for (i = 0; i < 100; i++) { + ASSERT(intolerant_eq(raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage)); + ASSERT(intolerant_eq(raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage)); + } + rtgrpblib_reset_raster(raster, 10, 10); + rtgrpblib_reset_raster(refraster, 10, 10); +} + + +static double +frand(double a, double b) +{ + int i = rand(); + double f = (double)i / (double)RAND_MAX; + double max = fmax(a, b); + double min = fmin(a, b); + return fma(f, max - min, min); +} + + int main(void) { - return 0; /* TODO add test */ + double x1, x2; + double y1, y2; + size_t i; + + raster = rtgrpblib_create_raster(10, 10); + ASSERT(raster); + refraster = rtgrpblib_create_raster(10, 10); + ASSERT(refraster); + srand((unsigned)(uintptr_t)raster); + + for (i = 0; i < 10000UL; i++) { +#ifndef ROWWISE_RESET_INKLEVEL + x1 = frand(-5, 15); + y1 = frand(-5, 15); + x2 = frand(-5, 15); + y2 = frand(-5, 15); +#else + x1 = frand(0, 10); + y1 = frand(-5, 15); + x2 = frand(-5, 10); + y2 = frand(-5, 15); +#endif + + check_draw_linear_bezier(x1, y1, x2, y2); + check_draw_linear_bezier(x1, x1, x2, x2); + check_draw_linear_bezier(x1, x2, x2, x1); + check_draw_linear_bezier(x1, y1, x2, y1); + check_draw_linear_bezier(x1, y1, x1, y2); + /* TODO test with zero draftness */ + } + + free(raster); + free(refraster); + return 0; } |