aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--common.h10
-rw-r--r--draw_linear_bezier_reference.c152
-rw-r--r--equations.c2
-rw-r--r--lines.c4
-rw-r--r--rtgrpblib_draw_cubic_bezier.c4
-rw-r--r--rtgrpblib_draw_linear_bezier.c67
-rw-r--r--rtgrpblib_draw_quadratic_bezier.c206
8 files changed, 337 insertions, 110 deletions
diff --git a/LICENSE b/LICENSE
index 0be2ccf..6ddac9a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
ISC License
-© 2023 Mattias Andrée <maandree@kth.se>
+© 2023 Mattias Andrée <m@maandree.se>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/common.h b/common.h
index 80f807c..f133898 100644
--- a/common.h
+++ b/common.h
@@ -145,12 +145,6 @@ tolerant_eq(double a, double b)
return iszeroish((a - b) / 100.0);
}
-static inline int
-intolerant_eq(double a, double b)
-{
- return fabs(a - b) < 1e-11;
-}
-
# define ASSERT(ASSERTION)\
do {\
if (!(ASSERTION)) {\
@@ -159,8 +153,8 @@ intolerant_eq(double a, double b)
}\
} while (0)
-# if 0
-static void
+# if 1
+static inline void
print_raster(const RASTER *r) {
size_t y, x;
fprintf(stderr, "\nOutline (area)\n");
diff --git a/draw_linear_bezier_reference.c b/draw_linear_bezier_reference.c
index dbfb87f..b7dab11 100644
--- a/draw_linear_bezier_reference.c
+++ b/draw_linear_bezier_reference.c
@@ -14,86 +14,94 @@
*/
-void
-draw_linear_bezier_reference(RASTER *restrict raster, double x1, double y1, double x2, double y2)
+static void
+draw_cell(RASTER *restrict raster, double x1, double y1, double x2, double y2, double dx, double dy,
+ double cxmin, double cxmax, double rxmin, double rxmax, double rymin, double rymax, ssize_t x, size_t cellY)
{
- double dx = x2 - x1;
- double dy = y2 - y1;
- int xdir = SIGNUM(dx);
- int ydir = SIGNUM(dy);
- double kx = dx / dy;
- double ky = dy / dx;
- double prevX, prevY, x, y, cx, cy, h2x, h2y;
- double xfloor, yfloor;
- ssize_t cellX, cellY;
+ double cy1, cy2, ydir = (double)SIGNUM(dy);
+ double rightedge, opposite, midadjacent;
size_t cell;
- prevX = x1;
- prevY = y1;
-
- for (; prevX != x2 || prevY != y2; prevX = x, prevY = y) {
- /* Find next vertical and next hozitonal grid line */
- x = xdir < 0 ? floor(prevX) : xdir > 0 ? ceil(prevX) : prevX;
- y = ydir < 0 ? floor(prevY) : ydir > 0 ? ceil(prevY) : prevY;
- x = iszeroish(x - prevX) ? x + xdir : x;
- y = iszeroish(y - prevY) ? y + ydir : y;
-
- /* Limit to the extend of the drawn line segment */
- if ((xdir < 0 && x < x2) || (xdir > 0 && x > x2))
- x = x2;
- if ((ydir < 0 && y < y2) || (ydir > 0 && y > y2))
- y = y2;
-
- /* Find next cell edge */
- if (xdir && ydir) {
- cy = y1 + (x - x1) * ky;
- cx = x1 + (y - y1) * kx;
- h2x = (cy - prevY) * (cy - prevY) + (x - prevX) * (x - prevX);
- h2y = (cx - prevX) * (cx - prevX) + (y - prevY) * (y - prevY);
- if (h2x < h2y)
- y = cy;
- else
- x = cx;
-
- /* Make sure loop will exit when we reach the end */
- if ((xdir < 0 && x <= x2) || (xdir > 0 && x >= x2) ||
- (ydir < 0 && y <= y2) || (ydir > 0 && y >= y2)) {
- x = x2;
- y = y2;
- }
- }
+ rightedge = cxmax;
+ cxmin = fmax(cxmin, rxmin);
+ cxmax = fmin(cxmax, rxmax);
+ cy1 = dx ? y1 + (cxmin - x1) * dy / dx : y1;
+ cy2 = dx ? y2 + (cxmax - x2) * dy / dx : y2;
+ cy1 = fmin(fmax(cy1, rymin), rymax);
+ cy2 = fmin(fmax(cy2, rymin), rymax);
- /* Select cell to draw in */
- xfloor = xdir >= 0 ? floor(prevX) : floor(x);
- yfloor = ydir >= 0 ? floor(prevY) : floor(y);
- cellX = (ssize_t)xfloor;
- cellY = (ssize_t)yfloor;
+ opposite = ydir * fabs(cy2 - cy1);
+ midadjacent = (cxmin + cxmax) / 2.0;
- /* Do not draw if above or below the raster */
- if (cellY < 0 || (size_t)cellY >= raster->height)
- continue;
+ if (x < 0) {
+ raster->cells[cellY].opposite_coverage += opposite;
+ raster->cells[cellY].cell_coverage += opposite;
+ } else if ((size_t)x >= raster->width) {
+ cell = cellY + (raster->width - 1);
+ raster->cells[cell].opposite_coverage += opposite;
+ } else {
+ cell = cellY + (size_t)x;
+ raster->cells[cell].opposite_coverage += opposite;
+ raster->cells[cell].cell_coverage += opposite * fabs(rightedge - midadjacent);
+ }
+}
- if (cellX < 0) {
- /* Draw on first column in raster of outside of raster on the left side,
- * with full horizontal coverage, `.opposite_coverage` one the actual
- * cell (outside of the raster) will contribute to the first column's
- * `.cell_coverage` */
- cell = (size_t)cellY * raster->width;
- raster->cells[cell].opposite_coverage += y - prevY;
- raster->cells[cell].cell_coverage += y - prevY;
+void
+draw_linear_bezier_reference(RASTER *restrict raster, double x1, double y1, double x2, double y2)
+{
+ ssize_t iwidth = (ssize_t)raster->width;
+ double width = (double)raster->width;
+ double height = (double)raster->height;
+ double dx = x2 - x1;
+ double dy = y2 - y1;
+ double fymin = fmin(fmax(fmin(y1, y2), 0.0), height);
+ double fymax = fmin(fmax(fmax(y1, y2), 0.0), height);
+ double floor_fymin = floor(fymin);
+ double ceil_fymax = ceil(fymax);
+ size_t ymin = (size_t)floor_fymin;
+ size_t ymax = (size_t)ceil_fymax;
+ size_t y, cellY;
+ double rowx1, rowx2;
+ double rxmin, rxmax, floor_rxmin;
+ double rymax, rymin, ceil_rxmax;
+ ssize_t x, xmin, xmax, xmin_cropped, xmax_cropped;
+ double cxmin, cxmax;
- } else if ((size_t)cellX >= raster->width) {
- /* If outside of the raster, on the right side, add to the last
- * columns contributions to the next column, so that the ink level
- * balances out to zero */
- cell = (size_t)cellY * raster->width + (raster->width - 1);
- raster->cells[cell].opposite_coverage += y - prevY;
+ ymax += (size_t)(ymax == ymin);
+ for (y = ymin; y < ymax; y++) {
+ rymin = (double)y;
+ rymax = (double)y + 1.0;
+ rymin = fmax(rymin, fymin);
+ rymax = fmin(rymax, fymax);
+ rowx1 = dy ? x1 + (rymin - y1) * dx / dy : x1;
+ rowx2 = dy ? x2 + (rymax - y2) * dx / dy : x2;
+ rxmin = fmin(rowx1, rowx2);
+ rxmax = fmax(rowx1, rowx2);
+ cellY = y * raster->width;
- } else {
- /* If inside the raster, just draw the line */
- cell = (size_t)cellY * raster->width + (size_t)cellX;
- raster->cells[cell].opposite_coverage += y - prevY;
- raster->cells[cell].cell_coverage += (y - prevY) * fabs(xfloor + 1.0 - (x + prevX) / 2.0);
+ floor_rxmin = floor(rxmin);
+ ceil_rxmax = ceil(rxmax);
+ xmin = (ssize_t)floor_rxmin;
+ xmax = (ssize_t)ceil_rxmax;
+ xmax += (ssize_t)(xmax == xmin);
+ xmin_cropped = xmin;
+ xmax_cropped = xmax;
+ if (xmin < 0.0) {
+ cxmin = (double)xmin;
+ cxmax = xmax < 0 ? (double)(xmax + 1) : 0.0;
+ draw_cell(raster, x1, y1, x2, y2, dx, dy, cxmin, cxmax, rxmin, rxmax, rymin, rymax, xmin, cellY);
+ xmin_cropped = 0;
+ }
+ if (xmax > iwidth) {
+ cxmin = fmax(floor_rxmin, width);
+ cxmax = (double)xmax;
+ draw_cell(raster, x1, y1, x2, y2, dx, dy, cxmin, cxmax, rxmin, rxmax, rymin, rymax, (ssize_t)cxmin, cellY);
+ xmax_cropped = iwidth;
+ }
+ for (x = xmin_cropped; x < xmax_cropped; x++) {
+ cxmin = (double)x;
+ cxmax = (double)x + 1.0;
+ draw_cell(raster, x1, y1, x2, y2, dx, dy, cxmin, cxmax, rxmin, rxmax, rymin, rymax, x, cellY);
}
}
}
diff --git a/equations.c b/equations.c
index 571fc26..2cf8bc9 100644
--- a/equations.c
+++ b/equations.c
@@ -302,6 +302,8 @@ check_cubic(double r1, double i1, double r2, double i2, double r3, double i3, do
for (i = 0; i < sizeof(found) / sizeof(*found); i++)
found[i] = (i >= nexpected || expected[i] < 0.0 + TOLERANCE || expected[i] > 1.0 - TOLERANCE);
if (!nexpected) {
+ if (!ngot) /* FIXME */
+ fprintf(stderr, "%lg, %lg, %lg, %lg, %lg, %lg, %lg, %i\n", r1, i1, r2, i2, r3, i3, k, strict_real);
ASSERT(!ngot);
return;
}
diff --git a/lines.c b/lines.c
index 4ac624a..a2e87be 100644
--- a/lines.c
+++ b/lines.c
@@ -242,8 +242,8 @@ check_against_reference(double x1, double y1, double x2, double y2)
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));
+ ASSERT(eq(raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage));
+ ASSERT(eq(raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage));
}
}
diff --git a/rtgrpblib_draw_cubic_bezier.c b/rtgrpblib_draw_cubic_bezier.c
index c68ad88..ca5f40b 100644
--- a/rtgrpblib_draw_cubic_bezier.c
+++ b/rtgrpblib_draw_cubic_bezier.c
@@ -165,12 +165,12 @@ rtgrpblib_draw_cubic_bezier(RASTER *restrict raster, double x1, double y1, doubl
/* Remove any segments above or below the raster */
y = evaluate_cubic_bezier(t, y1, y2, y3, y4);
- if (y < 0 || y >= (double)raster->height)
+ if (y < 0 || y > (double)raster->height)
continue;
/* If the segment is inside the raster, draw it, */
x = evaluate_cubic_bezier(t, x1, x2, x3, x4);
- if (0 <= x && x < (double)raster->width) {
+ if (0 <= x && x <= (double)raster->width) {
draw_bounded_cubic_bezier(raster, x1, y1, x2, y2, x3, y3, x4, y4, t1, t2);
continue;
}
diff --git a/rtgrpblib_draw_linear_bezier.c b/rtgrpblib_draw_linear_bezier.c
index bf9d41e..a2af58f 100644
--- a/rtgrpblib_draw_linear_bezier.c
+++ b/rtgrpblib_draw_linear_bezier.c
@@ -127,24 +127,65 @@ static RASTER *raster;
static RASTER *refraster;
+#ifdef ROWWISE_RESET_INKLEVEL
static void
-check_draw_linear_bezier(double x1, double y1, double x2, double y2)
+draw_right_edge_shadow(double x1, double y1, double x2, double y2)
+{
+ if (raster->draftness <= 0)
+ return;
+
+ if (x1 >= 10.0 && x2 >= 10.0) {
+ draw_linear_bezier_reference(raster, x1, y1, x2, y2);
+
+ } else if (x1 >= 10.0) {
+ y2 = y2 + (10.0 - x2) * (y2 - y1) / (x2 - x1);
+ x2 = 10.0;
+ draw_linear_bezier_reference(raster, x1, y1, x2, y2);
+
+ } else if (x2 >= 10.0) {
+ y1 = y1 + (10.0 - x1) * (y2 - y1) / (x2 - x1);
+ x1 = 10.0;
+ draw_linear_bezier_reference(raster, x1, y1, x2, y2);
+ }
+}
+#endif
+
+
+static void
+proper_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);
+#ifdef ROWWISE_RESET_INKLEVEL
+ draw_right_edge_shadow(x1, y1, x2, y2);
+#endif
+
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));
+ ASSERT(eq(raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage));
+ ASSERT(eq(raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage));
}
rtgrpblib_reset_raster(raster, 10, 10);
rtgrpblib_reset_raster(refraster, 10, 10);
}
+static void
+check_draw_linear_bezier(double x1, double y1, double x2, double y2)
+{
+ proper_check_draw_linear_bezier(floor(x1), floor(y1), floor(x2), floor(y2));
+ proper_check_draw_linear_bezier(floor(x1), y1, floor(x2), y2);
+ proper_check_draw_linear_bezier(x1, floor(y1), x2, floor(y2));
+ proper_check_draw_linear_bezier(x1, y1, x2, y2);
+}
+
+
static double
frand(double a, double b)
{
@@ -169,26 +210,26 @@ main(void)
ASSERT(refraster);
srand((unsigned)(uintptr_t)raster);
- for (i = 0; i < 10000UL; i++) {
-#ifndef ROWWISE_RESET_INKLEVEL
+ for (i = 0; i < 50000UL; i++) {
x1 = frand(-5, 15);
y1 = frand(-5, 15);
x2 = frand(-5, 15);
y2 = frand(-5, 15);
-#else
- /* TODO add tests the support higher upper bound */
- x1 = frand(0, 10); /* TODO fix lower bound */
- 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, y1, x2, y1);
check_draw_linear_bezier(x1, x2, x2, x1);
+ check_draw_linear_bezier(x1, y1, x1, y2);
+ check_draw_linear_bezier(x1, x1, x1, x1);
+ raster->draftness = -1;
+ check_draw_linear_bezier(x1, y1, x2, y2);
+ check_draw_linear_bezier(x1, x1, x2, x2);
check_draw_linear_bezier(x1, y1, x2, y1);
+ check_draw_linear_bezier(x1, x2, x2, x1);
check_draw_linear_bezier(x1, y1, x1, y2);
- /* TODO test with zero draftness */
+ check_draw_linear_bezier(x1, x1, x1, x1);
+ raster->draftness = 0.5;
}
free(raster);
diff --git a/rtgrpblib_draw_quadratic_bezier.c b/rtgrpblib_draw_quadratic_bezier.c
index 8aae11e..e2202c6 100644
--- a/rtgrpblib_draw_quadratic_bezier.c
+++ b/rtgrpblib_draw_quadratic_bezier.c
@@ -90,23 +90,22 @@ rtgrpblib_draw_quadratic_bezier(RASTER *restrict raster, double x1, double y1,
size_t nts = 0;
size_t i;
-#ifdef TODO /* untested */
/* Can we downgrade the curve to a linear Bézier curve?
*
* (y2 - y1)/(x2 - x1) = (y3 - y2)/(x3 - x2) = (y3 - y1)/(x3 - x1)
* (y2 - y1)/(x2 - x1) = (y3 - y2)/(x3 - x2)
* (y2 - y1)(x3 - x2) = (y3 - y2)(x2 - x1)
*/
- if ((y3 - y1) * (x3 - x2) == (y3 - y2) * (x2 - x1)) {
- if (x1 <= x2 && x2 <= x3 && y1 <= y2 && y2 <= y3)
- rtgrpblib_draw_linear_bezier(raster, x1, y1, x3, y3);
- else if (x1 <= x3 && x3 <= x2 && y1 <= y3 && y3 <= y2)
- rtgrpblib_draw_linear_bezier(raster, x1, y1, x2, y2);
- else
- rtgrpblib_draw_linear_bezier(raster, x2, y2, x3, y3);
+ if ((y2 - y1) * (x3 - x2) == (y3 - y2) * (x2 - x1)) {
+ /* Drawing (x1, y1)--(x2, y2) plus (x2, y2)--(x3, y3)
+ * is equivalent to drawing (x1, y1)--(x3, y3) because
+ * the result is signed and if (x2, y2) is outside the
+ * (x1, y1)--(x3, y3) line (x2, y2)--(x3, y3) erases
+ * the part that (x1, y1)--(x2, y2) extends to
+ * (x1, y1)--(x3, y3) */
+ rtgrpblib_draw_linear_bezier(raster, x1, y1, x3, y3);
return;
}
-#endif
/* Beginning and end of curve */
ts[nts++] = 0.0;
@@ -126,12 +125,12 @@ rtgrpblib_draw_quadratic_bezier(RASTER *restrict raster, double x1, double y1,
/* Remove any segments above or below the raster */
y = evaluate_quadratic_bezier(t, y1, y2, y3);
- if (y < 0 || y >= (double)raster->height)
+ if (y < 0 || y > (double)raster->height)
continue;
/* If the segment is inside the raster, draw it, */
x = evaluate_quadratic_bezier(t, x1, x2, x3);
- if (0 <= x && x < (double)raster->width) {
+ if (0 <= x && x <= (double)raster->width) {
draw_bounded_quadratic_bezier(raster, x1, y1, x2, y2, x3, y3, t1, t2);
continue;
}
@@ -157,10 +156,193 @@ rtgrpblib_draw_quadratic_bezier(RASTER *restrict raster, double x1, double y1,
#else
+static RASTER *raster;
+static RASTER *refraster;
+
+
+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);
+}
+
+
+static void
+check_line(double x1, double y1, double x2, double y2, double x3, double y3, int exact)
+{
+ size_t i;
+
+ alarm(5);
+ rtgrpblib_draw_quadratic_bezier(raster, x1, y1, x2, y2, x3, y3);
+
+ alarm(5);
+ rtgrpblib_draw_linear_bezier(refraster, x1, y1, x3, y3);
+
+ alarm(0);
+
+ if (exact) {
+ ASSERT(!memcmp(raster->cells, refraster->cells, 100 * sizeof(*raster->cells)));
+ } else {
+ for (i = 0; i < 100; i++) {
+ if (!eq(raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage))
+ fprintf(stderr, "c%02zu: %la ref: %la; diff: %lg=%la (tol: %la)\n", i, raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage, refraster->cells[i].cell_coverage - raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage - raster->cells[i].cell_coverage, TOLERANCE);
+ if (!eq(raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage))
+ fprintf(stderr, "o%02zu: %la ref: %la; diff: %lg=%la (tol: %la)\n", i, raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage, raster->cells[i].opposite_coverage - refraster->cells[i].opposite_coverage, raster->cells[i].opposite_coverage - refraster->cells[i].opposite_coverage, TOLERANCE);
+ }
+ for (i = 0; i < 100; i++) {
+ if (!eq(raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage) ||
+ !eq(raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage)) {
+ print_raster(refraster);
+ print_raster(raster);
+ }
+ ASSERT(eq(raster->cells[i].cell_coverage, refraster->cells[i].cell_coverage));
+ ASSERT(eq(raster->cells[i].opposite_coverage, refraster->cells[i].opposite_coverage));
+ }
+ }
+ rtgrpblib_reset_raster(raster, 10, 10);
+ rtgrpblib_reset_raster(refraster, 10, 10);
+}
+
+
+static void
+check_simple_lines(void)
+{
+ check_line(1, 1, 2, 2, 3, 3, 1);
+ check_line(1, 1, 3, 3, 2, 2, 1);
+ check_line(2, 2, 1, 1, 3, 3, 1);
+ check_line(2, 2, 3, 3, 1, 1, 1);
+ check_line(3, 3, 1, 1, 2, 2, 1);
+ check_line(3, 3, 2, 2, 1, 1, 1);
+ check_line(1, 1, 3, 3, 3, 3, 1);
+ check_line(1, 1, 1, 1, 3, 3, 1);
+
+ check_line(1, 4, 2, 4, 3, 4, 1);
+ check_line(1, 4, 3, 4, 2, 4, 1);
+ check_line(2, 4, 1, 4, 3, 4, 1);
+ check_line(2, 4, 3, 4, 1, 4, 1);
+ check_line(3, 4, 1, 4, 2, 4, 1);
+ check_line(3, 4, 2, 4, 1, 4, 1);
+ check_line(1, 4, 3, 4, 3, 4, 1);
+ check_line(1, 4, 1, 4, 3, 4, 1);
+
+ check_line(4, 1, 4, 2, 4, 3, 1);
+ check_line(4, 1, 4, 3, 4, 2, 1);
+ check_line(4, 2, 4, 1, 4, 3, 1);
+ check_line(4, 2, 4, 3, 4, 1, 1);
+ check_line(4, 3, 4, 1, 4, 2, 1);
+ check_line(4, 3, 4, 2, 4, 1, 1);
+ check_line(4, 1, 4, 3, 4, 3, 1);
+ check_line(4, 1, 4, 1, 4, 3, 1);
+}
+
+
+static void
+check_random_bounded_lines(int exact)
+{
+ double x1, x2, x3;
+ double y1, y2, y3;
+ double mid;
+ size_t i;
+
+ for (i = 0; i < 100000UL; i++) {
+ x1 = floor(frand(0, 11));
+ y1 = floor(frand(0, 11));
+ x3 = floor(frand(0, 11));
+ y3 = floor(frand(0, 11));
+ x1 -= (double)(x1 > 10);
+ x2 -= (double)(x2 > 10);
+ y1 -= (double)(y1 > 10);
+ y2 -= (double)(y2 > 10);
+ mid = frand(0, 1);
+
+ if (x3 - x1) {
+ x2 = floor(mid * (x3 - x1) + x1);
+ y2 = y1 + (x2 - x1) * (y3 - y1) / (x3 - x1);
+ } else if (y3 - y1) {
+ x2 = x1;
+ y2 = floor(mid * (y3 - y1) + y1);
+ } else {
+ x2 = x1;
+ y2 = y1;
+ }
+
+ if (!exact)
+ check_line(x1, y1, x2, y2, x3, y3, x2 == floor(x2) && y2 == floor(y2));
+ else if (x2 == floor(x2) && y2 == floor(y2))
+ check_line(x1, y1, x2, y2, x3, y3, 1);
+ }
+}
+
+
+static void
+check_random_unbounded_lines(int exact)
+{
+ double x1, x2, x3;
+ double y1, y2, y3;
+ double mid;
+ size_t i;
+
+ for (i = 0; i < 100000UL; i++) {
+ x1 = floor(frand(-5, 15));
+ y1 = floor(frand(-5, 15));
+ x3 = floor(frand(-5, 15));
+ y3 = floor(frand(-5, 15));
+ mid = frand(-2, 2);
+
+ if (x3 - x1) {
+ x2 = floor(mid * (x3 - x1) + x1);
+ y2 = y1 + (x2 - x1) * (y3 - y1) / (x3 - x1);
+ } else if (y3 - y1) {
+ x2 = x1;
+ y2 = floor(mid * (y3 - y1) + y1);
+ } else {
+ x2 = x1;
+ y2 = y1;
+ }
+
+ if (!exact)
+ check_line(x1, y1, x2, y2, x3, y3, x2 == floor(x2) && y2 == floor(y2));
+ else if (x2 == floor(x2) && y2 == floor(y2))
+ check_line(x1, y1, x2, y2, x3, y3, 1);
+ }
+}
+
+
int
main(void)
{
- return 0; /* TODO add test */
+ raster = rtgrpblib_create_raster(10, 10);
+ ASSERT(raster);
+ refraster = rtgrpblib_create_raster(10, 10);
+ ASSERT(refraster);
+ srand((unsigned)(uintptr_t)raster);
+
+ check_simple_lines();
+ check_random_bounded_lines(1);
+ check_random_unbounded_lines(1);
+ //TODO check_random_bounded_lines(0);
+ //TODO check_random_unbounded_lines(0);
+ raster->draftness = -1;
+ refraster->draftness = -1;
+ check_simple_lines();
+ check_random_bounded_lines(1);
+ check_random_unbounded_lines(1);
+#ifdef TODO_NOT_IMPLEMENTED
+ check_random_bounded_lines(0);
+ check_random_unbounded_lines(0);
+#endif
+ raster->draftness = 0.5;
+ refraster->draftness = 0.5;
+
+ /* TODO add tests */
+
+ free(raster);
+ free(refraster);
+ return 0;
}