mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-31 05:00:35 +00:00
Add union and merge functions and tests.
This commit is contained in:
parent
73f2c12815
commit
c25327f4ed
3 changed files with 138 additions and 1 deletions
|
@ -137,4 +137,33 @@ vrect_t *VRect_VSplit (const vrect_t *r, int x);
|
|||
*/
|
||||
vrect_t *VRect_Difference (const vrect_t *r, const vrect_t *s);
|
||||
|
||||
/** Return the union of the two rectangles.
|
||||
|
||||
The union rectangle will be big enough to entirely contain both \a r1
|
||||
and \a r2. An empty rectangle will be returned if both rectangles are
|
||||
empty.
|
||||
|
||||
\param r1 The first rectangle.
|
||||
\param r2 The second rectangle.
|
||||
\return The union of the two rectangles.
|
||||
\note It is the caller's responsibility to delete the returned rectangle.
|
||||
*/
|
||||
vrect_t *VRect_Union (const vrect_t *r1, const vrect_t *r2);
|
||||
|
||||
/** Return the rectangle representing the merge of the two given rectangles.
|
||||
|
||||
If the two given rectangles cannot be perfectly joined (either they
|
||||
intesect or subtracting them from the merged rectangle would result
|
||||
in scrap rectangles, null will be returned. Two empty rectangles will
|
||||
result in null being returned, but only one empty rectangle will result
|
||||
in a copy of the non-empty rectangle.
|
||||
|
||||
\param r1 The first rectangle to be merged.
|
||||
\param r2 The second rectangle to be merged.
|
||||
\return The merged rectangle, or null if the given rectangles
|
||||
cannot be merged.
|
||||
\note It is the caller's responsibility to delete the returned rectangle.
|
||||
*/
|
||||
vrect_t *VRect_Merge (const vrect_t *r, const vrect_t *s);
|
||||
|
||||
#endif//__QF_vrect_h
|
||||
|
|
|
@ -95,6 +95,31 @@ struct {
|
|||
{VRect_Difference, VR (3,3,2,2), VR (1,1,3,3), &de_15_0},
|
||||
|
||||
{VRect_Difference, VR (4,4,2,2), VR (1,1,3,3), &de_16_0},
|
||||
|
||||
{VRect_Union, VR (0, 0, 0, 0), VR (1, 1, -1, 1), 0, VR (1, 1, 1, -1), 1},
|
||||
{VRect_Union, VR (0, 0, 0, 0), VR (1, 1, 3, 3), 0, VR (1, 1, 3, 3), 1},
|
||||
{VRect_Union, VR (0, 0, 2, 5), VR (1, 1, -1, 1), 0, VR (0, 0, 2, 5), 1},
|
||||
{VRect_Union, VR (0, 0, 2, 5), VR (1, 1, 3, 3), 0, VR (0, 0, 4, 5), 1},
|
||||
|
||||
{VRect_Merge, VR (0, 0, 0, 0), VR (1, 1, -1, 1), 0},
|
||||
{VRect_Merge, VR (0, 0, 0, 0), VR (1, 1, 3, 3), 0, VR (1, 1, 3, 3), 1},
|
||||
{VRect_Merge, VR (0, 0, 2, 5), VR (1, 1, -1, 1), 0, VR (0, 0, 2, 5), 1},
|
||||
{VRect_Merge, VR (0, 0, 2, 5), VR (1, 1, 3, 3), 0},
|
||||
|
||||
{VRect_Merge, VR (0,0,2,2), VR (1,1,3,3), 0},
|
||||
{VRect_Merge, VR (0,0,5,2), VR (1,1,3,3), 0},
|
||||
{VRect_Merge, VR (2,0,2,2), VR (1,1,3,3), 0},
|
||||
{VRect_Merge, VR (3,0,2,2), VR (1,1,3,3), 0},
|
||||
|
||||
{VRect_Merge, VR (0,0,4,1), VR (1,1,3,3), 0},
|
||||
{VRect_Merge, VR (1,-1,3,1), VR (1,1,3,3), 0},
|
||||
{VRect_Merge, VR (0,4,4,1), VR (1,1,3,3), 0},
|
||||
{VRect_Merge, VR (1,5,3,1), VR (1,1,3,3), 0},
|
||||
|
||||
{VRect_Merge, VR (1,0,3,1), VR (1,1,3,3), 0, VR (1,0,3,4), 1},
|
||||
{VRect_Merge, VR (1,4,3,1), VR (1,1,3,3), 0, VR (1,1,3,4), 1},
|
||||
{VRect_Merge, VR (0,1,1,3), VR (1,1,3,3), 0, VR (0,1,4,3), 1},
|
||||
{VRect_Merge, VR (4,1,1,3), VR (1,1,3,3), 0, VR (1,1,4,3), 1},
|
||||
};
|
||||
#define num_tests (sizeof (tests) / sizeof (tests[0]))
|
||||
|
||||
|
@ -116,6 +141,9 @@ compare_rects (vrect_t *r1, vrect_t *r2)
|
|||
return 1;
|
||||
if (!r1 || !r2)
|
||||
return 0;
|
||||
// when both rects are empty, their exact values don't matter.
|
||||
if (VRect_IsEmpty (r1) && VRect_IsEmpty (r2))
|
||||
return 1;
|
||||
if (r1->x != r2->x || r1->y != r2->y
|
||||
|| r1->width != r2->width || r1->height != r2->height)
|
||||
return 0;
|
||||
|
|
|
@ -38,14 +38,18 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
|||
#include "QF/mathlib.h"
|
||||
#include "QF/vrect.h"
|
||||
|
||||
//#define TEST_MEMORY
|
||||
|
||||
#define RECT_BLOCK 128
|
||||
#ifndef TEST_MEMORY
|
||||
static vrect_t *free_rects;
|
||||
#endif
|
||||
|
||||
VISIBLE vrect_t *
|
||||
VRect_New (int x, int y, int width, int height)
|
||||
{
|
||||
vrect_t *r;
|
||||
|
||||
#ifndef TEST_MEMORY
|
||||
if (!free_rects) {
|
||||
int i;
|
||||
|
||||
|
@ -56,6 +60,9 @@ VRect_New (int x, int y, int width, int height)
|
|||
}
|
||||
r = free_rects;
|
||||
free_rects = free_rects->next;
|
||||
#else
|
||||
r = malloc (sizeof (vrect_t));
|
||||
#endif
|
||||
r->next = 0;
|
||||
r->x = x;
|
||||
r->y = y;
|
||||
|
@ -67,8 +74,12 @@ VRect_New (int x, int y, int width, int height)
|
|||
VISIBLE void
|
||||
VRect_Delete (vrect_t *rect)
|
||||
{
|
||||
#ifndef TEST_MEMORY
|
||||
rect->next = free_rects;
|
||||
free_rects = rect;
|
||||
#else
|
||||
free (rect);
|
||||
#endif
|
||||
}
|
||||
|
||||
VISIBLE vrect_t *
|
||||
|
@ -178,3 +189,72 @@ VRect_Difference (const vrect_t *r, const vrect_t *s)
|
|||
|
||||
return rects;
|
||||
}
|
||||
|
||||
VISIBLE vrect_t *
|
||||
VRect_Union (const vrect_t *r1, const vrect_t *r2)
|
||||
{
|
||||
int minx, miny;
|
||||
int maxx, maxy;
|
||||
|
||||
if (VRect_IsEmpty (r1))
|
||||
return VRect_New (r2->x, r2->y, r2->width, r2->height);
|
||||
|
||||
if (VRect_IsEmpty (r2))
|
||||
return VRect_New (r1->x, r1->y, r1->width, r1->height);
|
||||
|
||||
minx = min (VRect_MinX (r1), VRect_MinX (r2));
|
||||
miny = min (VRect_MinY (r1), VRect_MinY (r2));
|
||||
maxx = max (VRect_MaxX (r1), VRect_MaxX (r2));
|
||||
maxy = max (VRect_MaxY (r1), VRect_MaxY (r2));
|
||||
return VRect_New (minx, miny, maxx - minx, maxy - miny);
|
||||
}
|
||||
|
||||
VISIBLE vrect_t *
|
||||
VRect_Merge (const vrect_t *r1, const vrect_t *r2)
|
||||
{
|
||||
vrect_t *t, *u = 0;
|
||||
vrect_t *merge;
|
||||
|
||||
// cannot merge intersecting rectangles
|
||||
t = VRect_Intersect (r1, r2);
|
||||
if (!VRect_IsEmpty (t)) {
|
||||
VRect_Delete (t);
|
||||
return 0;
|
||||
}
|
||||
VRect_Delete (t);
|
||||
|
||||
merge = VRect_Union (r1, r2);
|
||||
if (VRect_IsEmpty (merge)) {
|
||||
VRect_Delete (merge);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the subtracting r1 from the union results in more than one rectangle
|
||||
// then r1 and r2 cannot be merged.
|
||||
t = VRect_Difference (merge, r1);
|
||||
if (t && t->next)
|
||||
goto cleanup;
|
||||
|
||||
// If subtracting r2 from the result of the previous difference results in
|
||||
// any rectangles, then r1 and r2 cannot be merged.
|
||||
if (t)
|
||||
u = VRect_Difference (t, r2);
|
||||
if (!u) {
|
||||
VRect_Delete (t);
|
||||
return merge;
|
||||
}
|
||||
cleanup:
|
||||
VRect_Delete (merge);
|
||||
// merge is used as a temp while freeing t and u
|
||||
while (u) {
|
||||
merge = u->next;
|
||||
VRect_Delete (u);
|
||||
u = merge;
|
||||
}
|
||||
while (t) {
|
||||
merge = t->next;
|
||||
VRect_Delete (t);
|
||||
t = merge;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue