aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--common.h21
-rw-r--r--rtgrpblib_draw_linear_bezier.c118
2 files changed, 119 insertions, 20 deletions
diff --git a/common.h b/common.h
index 2e8b8bc..80f807c 100644
--- a/common.h
+++ b/common.h
@@ -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;
}