From eac7a1fef3b07a73efe4239c8f043c0b5dd822cb Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 5 Feb 2023 11:21:28 +0100 Subject: Add draw_linear_bezier_reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- draw_linear_bezier_reference.c | 111 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 draw_linear_bezier_reference.c (limited to 'draw_linear_bezier_reference.c') diff --git a/draw_linear_bezier_reference.c b/draw_linear_bezier_reference.c new file mode 100644 index 0000000..6066946 --- /dev/null +++ b/draw_linear_bezier_reference.c @@ -0,0 +1,111 @@ +/* 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 -- cgit v1.2.3-70-g09d2