66 lines
2.2 KiB
C
66 lines
2.2 KiB
C
#ifndef KARLOS_RECT_H
|
|
#define KARLOS_RECT_H
|
|
|
|
#include <stdbool.h>
|
|
|
|
struct rect {
|
|
int x, y, xend, yend;
|
|
};
|
|
|
|
#define RECT_XYWH(x, y, w, h) (struct rect){ (x), (y), (x + w), (y + h) }
|
|
|
|
#define RECT_WIDTH(r) ((r).xend - (r).x)
|
|
#define RECT_HEIGHT(r) ((r).yend - (r).y)
|
|
#define RECT_XEND(r) ((r).xend)
|
|
#define RECT_YEND(r) ((r).yend)
|
|
|
|
// Moves `rect`.
|
|
void rect_translate(struct rect *rect, int delta_x, int delta_y);
|
|
void rect_translate_to(struct rect *rect, int new_x, int new_y);
|
|
|
|
// Clamps the rectangle `rect` to `boundary`.
|
|
// The rect is cut off at the edges of `boundary`.
|
|
void rect_clamp(struct rect *rect, const struct rect *boundary);
|
|
|
|
// Grows `rect` so that it encompasses both its original dimensions and `additional`.
|
|
void rect_union(struct rect *rect, const struct rect *additional);
|
|
|
|
// Grows (positive values) or shrinks (negative values) rect at specific sides.
|
|
#define RECT_RESIZE(rct, l, r, u, d) ((struct rect) { \
|
|
.x = (rct).x - l, \
|
|
.y = (rct).y - u, \
|
|
.xend = (rct).xend + r, \
|
|
.yend = (rct).yend + d, \
|
|
})
|
|
|
|
#define RECT_RESIZE_ALL(rct, val) RECT_RESIZE(rct, val, val, val, val)
|
|
|
|
// Rectangle is moved to lie inside the surrounding rect.
|
|
// It is also clamped to the surrounding rect.
|
|
// `rect` may be `NULL`, in which case it describes the entire `surrounding` rect.
|
|
// `surrounding` may not be `NULL`;
|
|
//
|
|
// Example:
|
|
// struct rect rect = RECT_XYWH(5, 10, 100, 100);
|
|
// struct rect surrounding = RECT_XYWH(200, 200, 50, 500);
|
|
// struct rect result = rect_local_to_global(&rect, &surrounding);
|
|
// ASSERT(result.x == 205 && result.y == 210);
|
|
// ASSERT(RECT_WIDTH(result) == 45 && RECT_HEIGHT(result) == 100);
|
|
struct rect rect_local_to_global(const struct rect *rect, const struct rect *surrounding);
|
|
|
|
#define RECT_EMPTY RECT_XYWH(0, 0, 0, 0)
|
|
#define RECT_IS_DEGENERATE(r) ((r).x > (r).xend || (r).y > (r).yend)
|
|
#define RECT_IS_EMPTY(r) ((r).x >= (r).xend || (r).y >= (r).yend)
|
|
#define RECT_AREA(r) (RECT_IS_EMPTY(r) ? 0 : (unsigned)((r).xend - (r).x) * ((r).yend - (r).y))
|
|
|
|
#define RECT_EQUAL(a, b) \
|
|
(a).x == (b).x \
|
|
&& (a).y == (b).y \
|
|
&& (a).xend == (b).xend \
|
|
&& (a).yend == (b).yend \
|
|
|
|
#define RECT_CONTAINS(r, vx, vy) \
|
|
((vx) >= (r).x && (vy) >= (r).y \
|
|
&& (vx) < RECT_XEND(r) && (vy) < RECT_YEND(r))
|
|
|
|
#endif
|