/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef TEST /* * The implementation in this fill is not supposed to be fast, * it is supposed to be absolutely correct. The implementation * shall be as clear and obvious as possible. It is important * that everything written to cells is as precise as possible * and that the function behavious correctly when outside the * raster. This implementation shall be usable to generate an * as perfect as possible rasterisation and shall be usable to * test the correctness and accuracy of the fast implementation. */ void draw_linear_bezier_reference(RASTER *restrict raster, double x1, double y1, double x2, double y2) { 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; 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 = x == prevX ? x + xdir : x; y = 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)) x = x2; if ((ydir < 0 && y < y2) || (ydir > 0 && y > y2)) y = y2; } /* 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; /* Do not draw if above or below the raster*/ if (cellY < 0 || (size_t)cellY >= raster->height) continue; 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; } 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; } 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(fmax(ceil(x), ceil(prevX)) - (x + prevX) / 2.0); } } } #else int main(void) { return 0; /* TODO add test */ } #endif