From d4efd1d9ab7947fcc6097f705a5dfb25b88023ab Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 21 Mar 2022 15:35:34 -0400 Subject: [PATCH] Add a bounding box type graphene_rect_t is not well-suited for this purpose, since you end up with floating-point precision problems at the upper bound (x + width, y + height). --- gsk/gskboundingboxprivate.h | 100 ++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 gsk/gskboundingboxprivate.h diff --git a/gsk/gskboundingboxprivate.h b/gsk/gskboundingboxprivate.h new file mode 100644 index 0000000000..45708b424f --- /dev/null +++ b/gsk/gskboundingboxprivate.h @@ -0,0 +1,100 @@ +#pragma once + +#include + +G_BEGIN_DECLS + +typedef struct _GskBoundingBox GskBoundingBox; + +struct _GskBoundingBox { + graphene_point_t min; + graphene_point_t max; +}; + +static inline GskBoundingBox * +gsk_bounding_box_init (GskBoundingBox *self, + const graphene_point_t *a, + const graphene_point_t *b) +{ + self->min.x = MIN (a->x, b->x); + self->min.y = MIN (a->y, b->y); + self->max.x = MAX (a->x, b->x); + self->max.y = MAX (a->y, b->y); + return self; +} + +static inline GskBoundingBox * +gsk_bounding_box_init_copy (GskBoundingBox *self, + const GskBoundingBox *src) +{ + self->min = src->min; + self->max = src->max; + return self; +} + +static inline GskBoundingBox * +gsk_bounding_box_init_from_rect (GskBoundingBox *self, + const graphene_rect_t *bounds) +{ + self->min = bounds->origin; + self->max.x = bounds->origin.x + bounds->size.width; + self->max.y = bounds->origin.y + bounds->size.height; + return self; +} + +static inline void +gsk_bounding_box_expand (GskBoundingBox *self, + const graphene_point_t *p) +{ + self->min.x = MIN (self->min.x, p->x); + self->min.y = MIN (self->min.y, p->y); + self->max.x = MAX (self->max.x, p->x); + self->max.y = MAX (self->max.y, p->y); +} + +static inline graphene_rect_t * +gsk_bounding_box_to_rect (const GskBoundingBox *self, + graphene_rect_t *rect) +{ + rect->origin = self->min; + rect->size.width = self->max.x - self->min.x; + rect->size.height = self->max.y - self->min.y; + return rect; +} + +static inline gboolean +gsk_bounding_box_contains_point (const GskBoundingBox *self, + const graphene_point_t *p) +{ + return self->min.x <= p->x && p->x <= self->max.x && + self->min.y <= p->y && p->y <= self->max.y; +} + +static inline gboolean +gsk_bounding_box_contains_point_with_epsilon (const GskBoundingBox *self, + const graphene_point_t *p, + float epsilon) +{ + return self->min.x - epsilon <= p->x && p->x <= self->max.x + epsilon && + self->min.y - epsilon <= p->y && p->y <= self->max.y + epsilon; +} + +static inline gboolean +gsk_bounding_box_intersection (const GskBoundingBox *a, + const GskBoundingBox *b, + GskBoundingBox *res) +{ + graphene_point_t min, max; + + min.x = MAX (a->min.x, b->min.x); + min.y = MAX (a->min.y, b->min.y); + max.x = MIN (a->max.x, b->max.x); + max.y = MIN (a->max.y, b->max.y); + + if (res) + gsk_bounding_box_init (res, &min, &max); + + return min.x <= max.x && min.y <= max.y; +} + +G_END_DECLS