From 4df563948b0c4086c7be5cb0ef453570d2ec40a0 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 5 Feb 2023 12:11:30 +0100 Subject: Add tests and documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 11 ++- common.h | 3 + ...kensnittsglyfrasteriseringsprogrambiblioteket.h | 105 ++++++++++++++++++++- rtgrpblib_create_raster.c | 45 ++++++++- rtgrpblib_reset_raster.c | 93 +++++++++++++++++- rtgrpblib_set_draftness.c | 2 +- sorting.c | 28 +++++- 7 files changed, 271 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 370c2fe..300fb5f 100644 --- a/Makefile +++ b/Makefile @@ -16,19 +16,20 @@ LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) LIB_NAME = rifunktionsteckensnittsglyfrasteriseringsprogrambiblioteket +# OBJ is sorted in testing order OBJ =\ equations.o\ - lines.o\ sorting.o\ - draw_linear_bezier_reference.o\ rtgrpblib_create_raster.o\ + rtgrpblib_reset_raster.o\ + rtgrpblib_set_draftness.o\ + draw_linear_bezier_reference.o\ + lines.o\ rtgrpblib_draw_circular_arc.o\ rtgrpblib_draw_linear_bezier.o\ rtgrpblib_draw_quadratic_bezier.o\ rtgrpblib_draw_cubic_bezier.o\ - rtgrpblib_fill_shapes.o\ - rtgrpblib_reset_raster.o\ - rtgrpblib_set_draftness.o + rtgrpblib_fill_shapes.o HDR =\ lib$(LIB_NAME).h\ diff --git a/common.h b/common.h index 2436a6a..67a1c62 100644 --- a/common.h +++ b/common.h @@ -29,6 +29,8 @@ #define SIGNUM(X) (((X) > 0) - ((X) < 0)) +#define DEFAULT_DRAFTNESS 0.5 + #define draw_vertical_line_opposite_only(...) @@ -66,6 +68,7 @@ typedef struct rtgrpblib_cell { typedef struct rtgrpblib_raster { size_t height; size_t width; + size_t size; double draftness; /* TODO support 0 */ CELL cells[]; } RASTER; diff --git a/librifunktionsteckensnittsglyfrasteriseringsprogrambiblioteket.h b/librifunktionsteckensnittsglyfrasteriseringsprogrambiblioteket.h index fffeae7..97d57c3 100644 --- a/librifunktionsteckensnittsglyfrasteriseringsprogrambiblioteket.h +++ b/librifunktionsteckensnittsglyfrasteriseringsprogrambiblioteket.h @@ -5,36 +5,133 @@ #include +/** + * Object that the library draws on, is converted to + * an ink-level image using the `rtgrpblib_fill_shapes` + * function. This object also contain drawing + * configurations. + */ typedef struct rtgrpblib_raster RTGRPBLIB_RASTER; +/** + * Create a buffer that the library can use for drawing + * + * @param width The width of the buffer + * @param height The height of the buffer + * @return Drawing buffer, which can be deallocated with (3), + * or `NULL` on failure + * + * @throws EINVAL `width` or `height` is zero + * @throws ENOMEM Cannot allocate enough memory + * + * @seealso rtgrpblib_reset_raster + */ RTGRPBLIB_RASTER *rtgrpblib_create_raster(size_t width, size_t height); + +/** + * Reshape and clear a drawing buffer + * + * @param raster The buffer to reshape and clear + * @param width The new width of the buffer + * @param height The new height of the buffer + * @return 0 on success, -1 on failure + * + * @throws EINVAL `width` or `height` is zero + * @throws EINVAL The buffers new area size exceeds its original area size + */ int rtgrpblib_reset_raster(RTGRPBLIB_RASTER *raster, size_t width, size_t height); + +/** + * Reconfigure a drawing buffer with a new draftness value + * + * When drawing a curve, the size of each step the library + * takes will be proportional to the draftness value, but + * will also depend on other factors. Doubling the draftness + * value with halve (disregarind overheads) the time it takes + * to draw any given curve. + * + * @param raster The drawing buffer to reconfigure + * @param draftness The new draftness value, must be positive + */ void rtgrpblib_set_draftness(RTGRPBLIB_RASTER *raster, double draftness); + +/** + * Create an image of the drawings applied to a drawing buffer + * + * All drawn shapes must be closed + * + * Shapes that are drawn in the same angular direction add to + * each other, shapes that are drawn in opposite angular + * directions subtract from each other + * + * @param image Output buffer, need not be initialised, but + * shall have an allocation size of `rowsize` + * multiplied by the height of `raster` and + * by `sizeof(double)` + * @param rowsize The number of elements in `image` per row, + * must be at least the width of `raster` + * @param raster The drawing buffer + * + * @seealso rtgrpblib_reset_raster + */ void rtgrpblib_fill_shapes(double *restrict image, size_t rowsize, const RTGRPBLIB_RASTER *raster); + +/** + * Draw a line between two points + * + * @param raster The drawing buffer + * @param x1, y1 The starting point + * @param x2, y2 The end point + */ void rtgrpblib_draw_linear_bezier(RTGRPBLIB_RASTER *restrict raster, double x1, double y1, double x2, double y2); +/** + * Draw a quadratic bézier curve + * + * @param raster The drawing buffer + * @param x1, y1 The starting point + * @param x2, y2 The control point + * @param x3, y3 The end point + */ void rtgrpblib_draw_quadratic_bezier(RTGRPBLIB_RASTER *restrict raster, double x1, double y1, double x2, double y2, double x3, double y3); -void rtgrpblib_draw_cubic_bezier(RTGRPBLIB_RASTER *restrict raster, +/** + * Draw a cubic bézier curve + * + * @param raster The drawing buffer + * @param x1, y1 The starting point + * @param x2, y2 The first control point + * @param x3, y3 The second control point + * @param x4, y4 The end point + */ +void rtgrpblib_draw_cubic_bezier(RTGRPBLIB_RASTER *restrict raster, /* needed for OpenType */ double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4); -void rtgrpblib_draw_circular_arc(RTGRPBLIB_RASTER *restrict raster, +/** + * Draw a cricular arc + * + * @param raster The drawing buffer + * @param x0, y0 The midpoint of the ellipse + * @param semiwidth Half the width of the ellipse + * @param semiheight Half the height of the ellipse + * @param start The angular starting point of the arc, in radians + * @param end The angular end point of the arc, in radians + */ +void rtgrpblib_draw_circular_arc(RTGRPBLIB_RASTER *restrict raster, /* needed for outline stoking */ double x0, double y0, double semiwidth, double semiheight, double start, double end); -/* TODO add support for outlining */ - #endif diff --git a/rtgrpblib_create_raster.c b/rtgrpblib_create_raster.c index 89ebad6..cbc69f2 100644 --- a/rtgrpblib_create_raster.c +++ b/rtgrpblib_create_raster.c @@ -7,6 +7,7 @@ RASTER * rtgrpblib_create_raster(size_t width, size_t height) { RASTER *raster; + size_t size; if (!width || !height) { errno = EINVAL; @@ -15,7 +16,8 @@ rtgrpblib_create_raster(size_t width, size_t height) if (width > (SIZE_MAX - offsetof(RASTER, cells)) / sizeof(*raster->cells) / height) goto enomem; - raster = calloc(1, offsetof(RASTER, cells) + height * width * sizeof(*raster->cells)); + size = width * height; + raster = calloc(1, offsetof(RASTER, cells) + size * sizeof(*raster->cells)); if (!raster) { enomem: errno = ENOMEM; @@ -24,7 +26,8 @@ rtgrpblib_create_raster(size_t width, size_t height) raster->width = width; raster->height = height; - raster->draftness = 0.5; + raster->size = size; + raster->draftness = DEFAULT_DRAFTNESS; return raster; } @@ -34,7 +37,43 @@ rtgrpblib_create_raster(size_t width, size_t height) int main(void) { - return 0; /* TODO add test */ + RASTER *raster; + size_t i, n; + + errno = 0; + ASSERT(!rtgrpblib_create_raster(0, 1)); + ASSERT(errno == EINVAL); + + errno = 0; + ASSERT(!rtgrpblib_create_raster(1, 0)); + ASSERT(errno == EINVAL); + + errno = 0; + ASSERT(!rtgrpblib_create_raster(0, 0)); + ASSERT(errno == EINVAL); + + errno = 0; + ASSERT(!rtgrpblib_create_raster(SIZE_MAX - offsetof(RASTER, cells) + 1, 1)); + ASSERT(errno == ENOMEM); + + errno = 0; + ASSERT(!rtgrpblib_create_raster(1, SIZE_MAX - offsetof(RASTER, cells) + 1)); + ASSERT(errno == ENOMEM); + + raster = rtgrpblib_create_raster(10, 20); + ASSERT(raster); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + ASSERT(raster->size == raster->width * raster->height); + ASSERT(raster->draftness == DEFAULT_DRAFTNESS); + n = raster->width * raster->height; + for (i = 0; i < n; i++) { + ASSERT(!raster->cells[i].cell_coverage); + ASSERT(!raster->cells[i].opposite_coverage); + } + + free(raster); + return 0; } #endif diff --git a/rtgrpblib_reset_raster.c b/rtgrpblib_reset_raster.c index 2cfef42..a3b81df 100644 --- a/rtgrpblib_reset_raster.c +++ b/rtgrpblib_reset_raster.c @@ -6,7 +6,7 @@ int rtgrpblib_reset_raster(RASTER *raster, size_t width, size_t height) { - if (!width || !height || width > raster->width * raster->height / height) { + if (!width || !height || width > raster->size / height) { errno = EINVAL; return -1; } @@ -23,7 +23,96 @@ rtgrpblib_reset_raster(RASTER *raster, size_t width, size_t height) int main(void) { - return 0; /* TODO add test */ + + RASTER *raster; + size_t i, n, size; + + raster = rtgrpblib_create_raster(10, 20); + ASSERT(raster); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + raster->draftness = 10; + size = raster->width * raster->height; + ASSERT(raster->size == size); + + errno = 0; + ASSERT(rtgrpblib_reset_raster(raster, 10, 21) == -1); + ASSERT(errno == EINVAL); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + + errno = 0; + ASSERT(rtgrpblib_reset_raster(raster, 11, 20) == -1); + ASSERT(errno == EINVAL); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + + errno = 0; + ASSERT(rtgrpblib_reset_raster(raster, 1, 0) == -1); + ASSERT(errno == EINVAL); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + + errno = 0; + ASSERT(rtgrpblib_reset_raster(raster, 0, 1) == -1); + ASSERT(errno == EINVAL); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + + errno = 0; + ASSERT(rtgrpblib_reset_raster(raster, 0, 0) == -1); + ASSERT(errno == EINVAL); + ASSERT(raster->width == 10); + ASSERT(raster->height == 20); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + + memset(raster->cells, 100, raster->size * sizeof(*raster->cells)); + ASSERT(!rtgrpblib_reset_raster(raster, 5, 10)); + ASSERT(raster->width == 5); + ASSERT(raster->height == 10); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + n = raster->width * raster->height; + for (i = 0; i < n; i++) { + ASSERT(!raster->cells[i].cell_coverage); + ASSERT(!raster->cells[i].opposite_coverage); + } + + memset(raster->cells, 100, raster->size * sizeof(*raster->cells)); + ASSERT(!rtgrpblib_reset_raster(raster, 5, 30)); + ASSERT(raster->width == 5); + ASSERT(raster->height == 30); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + n = raster->width * raster->height; + for (i = 0; i < n; i++) { + ASSERT(!raster->cells[i].cell_coverage); + ASSERT(!raster->cells[i].opposite_coverage); + } + + memset(raster->cells, 100, raster->size * sizeof(*raster->cells)); + ASSERT(!rtgrpblib_reset_raster(raster, 15, 10)); + ASSERT(raster->width == 15); + ASSERT(raster->height == 10); + ASSERT(raster->size == size); + ASSERT(raster->draftness == 10); + n = raster->width * raster->height; + for (i = 0; i < n; i++) { + ASSERT(!raster->cells[i].cell_coverage); + ASSERT(!raster->cells[i].opposite_coverage); + } + + free(raster); + return 0; } #endif diff --git a/rtgrpblib_set_draftness.c b/rtgrpblib_set_draftness.c index dbdeed0..d35222f 100644 --- a/rtgrpblib_set_draftness.c +++ b/rtgrpblib_set_draftness.c @@ -15,7 +15,7 @@ rtgrpblib_set_draftness(RTGRPBLIB_RASTER *raster, double draftness) int main(void) { - return 0; /* TODO add test */ + return 0; /* why test something this trivial */ } #endif diff --git a/sorting.c b/sorting.c index e4bfdaf..2738081 100644 --- a/sorting.c +++ b/sorting.c @@ -18,7 +18,33 @@ doublepcmp(const void *avp, const void *bvp) int main(void) { - return 0; /* TODO add test */ + double a, b; + + a = 1.0, b = 1.0; + ASSERT(doublepcmp(&a, &b) == 0); + ASSERT(doublepcmp(&b, &a) == -doublepcmp(&a, &b)); + + a = -1.0, b = 1.0; + ASSERT(doublepcmp(&a, &b) == -1); + ASSERT(doublepcmp(&b, &a) == -doublepcmp(&a, &b)); + + a = 1.0, b = -1.0; + ASSERT(doublepcmp(&a, &b) == +1); + ASSERT(doublepcmp(&b, &a) == -doublepcmp(&a, &b)); + + a = 0.0, b = 0.0; + ASSERT(doublepcmp(&a, &b) == 0); + ASSERT(doublepcmp(&b, &a) == -doublepcmp(&a, &b)); + + a = -1.0, b = 2.5; + ASSERT(doublepcmp(&a, &b) == -1); + ASSERT(doublepcmp(&b, &a) == -doublepcmp(&a, &b)); + + a = 1.0, b = -2.5; + ASSERT(doublepcmp(&a, &b) == +1); + ASSERT(doublepcmp(&b, &a) == -doublepcmp(&a, &b)); + + return 0; } -- cgit v1.2.3-70-g09d2