mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-05-31 00:30:57 +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);
|
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
|
#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 (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_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]))
|
#define num_tests (sizeof (tests) / sizeof (tests[0]))
|
||||||
|
|
||||||
|
@ -116,6 +141,9 @@ compare_rects (vrect_t *r1, vrect_t *r2)
|
||||||
return 1;
|
return 1;
|
||||||
if (!r1 || !r2)
|
if (!r1 || !r2)
|
||||||
return 0;
|
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
|
if (r1->x != r2->x || r1->y != r2->y
|
||||||
|| r1->width != r2->width || r1->height != r2->height)
|
|| r1->width != r2->width || r1->height != r2->height)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -38,14 +38,18 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
||||||
#include "QF/mathlib.h"
|
#include "QF/mathlib.h"
|
||||||
#include "QF/vrect.h"
|
#include "QF/vrect.h"
|
||||||
|
|
||||||
|
//#define TEST_MEMORY
|
||||||
|
|
||||||
#define RECT_BLOCK 128
|
#define RECT_BLOCK 128
|
||||||
|
#ifndef TEST_MEMORY
|
||||||
static vrect_t *free_rects;
|
static vrect_t *free_rects;
|
||||||
|
#endif
|
||||||
|
|
||||||
VISIBLE vrect_t *
|
VISIBLE vrect_t *
|
||||||
VRect_New (int x, int y, int width, int height)
|
VRect_New (int x, int y, int width, int height)
|
||||||
{
|
{
|
||||||
vrect_t *r;
|
vrect_t *r;
|
||||||
|
#ifndef TEST_MEMORY
|
||||||
if (!free_rects) {
|
if (!free_rects) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -56,6 +60,9 @@ VRect_New (int x, int y, int width, int height)
|
||||||
}
|
}
|
||||||
r = free_rects;
|
r = free_rects;
|
||||||
free_rects = free_rects->next;
|
free_rects = free_rects->next;
|
||||||
|
#else
|
||||||
|
r = malloc (sizeof (vrect_t));
|
||||||
|
#endif
|
||||||
r->next = 0;
|
r->next = 0;
|
||||||
r->x = x;
|
r->x = x;
|
||||||
r->y = y;
|
r->y = y;
|
||||||
|
@ -67,8 +74,12 @@ VRect_New (int x, int y, int width, int height)
|
||||||
VISIBLE void
|
VISIBLE void
|
||||||
VRect_Delete (vrect_t *rect)
|
VRect_Delete (vrect_t *rect)
|
||||||
{
|
{
|
||||||
|
#ifndef TEST_MEMORY
|
||||||
rect->next = free_rects;
|
rect->next = free_rects;
|
||||||
free_rects = rect;
|
free_rects = rect;
|
||||||
|
#else
|
||||||
|
free (rect);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VISIBLE vrect_t *
|
VISIBLE vrect_t *
|
||||||
|
@ -178,3 +189,72 @@ VRect_Difference (const vrect_t *r, const vrect_t *s)
|
||||||
|
|
||||||
return rects;
|
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…
Add table
Add a link
Reference in a new issue