diff options
Diffstat (limited to 'firmware/common/rectangle.c')
-rw-r--r-- | firmware/common/rectangle.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/firmware/common/rectangle.c b/firmware/common/rectangle.c new file mode 100644 index 0000000000..3ce09f5145 --- /dev/null +++ b/firmware/common/rectangle.c @@ -0,0 +1,141 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2022 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "rectangle.h" +#include "system.h" + +bool rect_contains(const struct rectangle *ra, const struct rectangle *rb) +{ + return ra->x <= rb->x && rb->x + rb->w < ra->x + ra->w && + ra->y <= rb->y && rb->y + rb->h < ra->y + ra->h; +} + +bool rect_overlap(const struct rectangle *ra, const struct rectangle *rb) +{ + return ra->x + ra->w > rb->x && rb->x + rb->w > ra->x && + ra->y + ra->h > rb->y && rb->y + rb->h > ra->y; +} + +bool rect_intersect(const struct rectangle *ra, const struct rectangle *rb, + struct rectangle *r_out) +{ + if (!rect_valid(ra) || !rect_valid(rb)) + return false; + + int x = MAX(ra->x, rb->x); + int y = MAX(ra->y, rb->y); + int w = MIN(ra->x + ra->w, rb->x + rb->w) - x; + int h = MIN(ra->y + ra->h, rb->y + rb->h) - y; + + r_out->x = x; + r_out->y = y; + r_out->w = w; + r_out->h = h; + + return w > 0 && h > 0; +} + +void rect_union(const struct rectangle *ra, const struct rectangle *rb, + struct rectangle *r_out) +{ + if (!rect_valid(ra)) { + *r_out = *rb; + } else if (!rect_valid(rb)) { + *r_out = *ra; + } else { + int x = MIN(ra->x, rb->x); + int y = MIN(ra->y, rb->y); + int w = MAX(ra->x + ra->w, rb->x + rb->w) - x; + int h = MAX(ra->y + ra->h, rb->y + rb->h) - y; + + r_out->x = x; + r_out->y = y; + r_out->w = w; + r_out->h = h; + } +} + +int rect_difference(const struct rectangle *rect, + const struct rectangle *rsub, + struct rectangle rects_out[4]) +{ + if (!rect_valid(rect) || !rect_valid(rsub)) { + rects_out[0] = *rect; + return 1; + } + + int x0 = MAX(rect->x, rsub->x); + int y0 = MAX(rect->y, rsub->y); + int x1 = MIN(rect->x + rect->w, rsub->x + rsub->w); + int y1 = MIN(rect->y + rect->h, rsub->y + rsub->h); + + /* no intersection */ + if (x1 - x0 <= 0 || y1 - y0 <= 0) { + rects_out[0] = *rect; + return 1; + } + + /* rect + * +-------------+ + * | . 2 . | + * | +-----+ | + * | 0 |rsub | 1 | + * | +-----+ | + * | . 3 . | + * +-------------+ + */ + + int n = 0; + + if (rect->x < x0) { + rects_out[n].x = rect->x; + rects_out[n].y = rect->y; + rects_out[n].w = x0 - rect->x; + rects_out[n].h = rect->h; + n++; + } + + if (x1 < rect->x + rect->w) { + rects_out[n].x = x1; + rects_out[n].y = rect->y; + rects_out[n].w = rect->x + rect->w - x1; + rects_out[n].h = rect->h; + n++; + } + + if (rect->y < y0) { + rects_out[n].x = x0; + rects_out[n].y = rect->y; + rects_out[n].w = x1 - x0; + rects_out[n].h = y0 - rect->y; + n++; + } + + if (y1 < rect->y + rect->h) { + rects_out[n].x = x0; + rects_out[n].y = y1; + rects_out[n].w = x1 - x0; + rects_out[n].h = rect->y + rect->h - y1; + n++; + } + + return n; +} |