* eina: improve QuadTree API.

SVN revision: 48482
This commit is contained in:
Cedric BAIL 2010-04-30 17:04:28 +00:00
parent c98e00eec0
commit 6caac50006
5 changed files with 140 additions and 70 deletions

View File

@ -21,7 +21,7 @@
#include "eina_config.h"
#include "eina_array.h"
#include "eina_inlist.h"
typedef struct _Eina_QuadTree Eina_QuadTree;
typedef struct _Eina_QuadTree_Item Eina_QuadTree_Item;
@ -39,6 +39,7 @@ EAPI Eina_QuadTree *eina_quadtree_new(size_t w, size_t h,
Eina_Quad_Callback horizontal);
EAPI void eina_quadtree_free(Eina_QuadTree *q);
EAPI void eina_quadtree_resize(Eina_QuadTree *q, size_t w, size_t h);
EAPI void eina_quadtree_cycle(Eina_QuadTree *q);
EAPI Eina_QuadTree_Item *eina_quadtree_add(Eina_QuadTree *q, const void *object);
EAPI Eina_Bool eina_quadtree_del(Eina_QuadTree_Item *object);
@ -46,7 +47,8 @@ EAPI Eina_Bool eina_quadtree_change(Eina_QuadTree_Item *object);
EAPI Eina_Bool eina_quadtree_hide(Eina_QuadTree_Item *object);
EAPI Eina_Bool eina_quadtree_show(Eina_QuadTree_Item *object);
EAPI void eina_quadtree_collide(Eina_Array *result, Eina_QuadTree *q,
int x, int y, size_t w, size_t h);
EAPI Eina_Inlist *eina_quadtree_collide(Eina_QuadTree *q,
int x, int y, int w, int h);
EAPI void *eina_quadtree_object(Eina_Inlist *list);
#endif

View File

@ -94,6 +94,9 @@ struct _Eina_QuadTree
Eina_Trash *root_trash;
Eina_Mempool *root_mp;
Eina_Inlist *cached;
Eina_Rectangle target;
size_t index;
struct {
@ -107,6 +110,7 @@ struct _Eina_QuadTree
} geom;
Eina_Bool resize : 1;
Eina_Bool lost : 1;
};
struct _Eina_QuadTree_Root
@ -591,6 +595,8 @@ eina_quadtree_new(size_t w, size_t h,
result->root_mp = eina_mempool_add("chained_mempool", "QuadTree Root", NULL,
sizeof (Eina_QuadTree_Root), 32);
result->lost = EINA_TRUE;
EINA_MAGIC_SET(result, EINA_MAGIC_QUADTREE);
return result;
@ -718,11 +724,19 @@ eina_quadtree_hide(Eina_QuadTree_Item *object)
EAPI Eina_Bool
eina_quadtree_show(Eina_QuadTree_Item *object)
{
size_t index;
EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
object->index = object->quad->index++;
index = object->quad->index++;
if (object->index == index
&& object->visible)
return EINA_TRUE;
object->index = index;
if (object->root)
object->root->sorted = EINA_FALSE;
object->quad->lost = EINA_TRUE;
if (object->visible) return EINA_TRUE;
@ -733,19 +747,12 @@ eina_quadtree_show(Eina_QuadTree_Item *object)
return EINA_TRUE;
}
EAPI void
eina_quadtree_collide(Eina_Array *result,
Eina_QuadTree *q, int x, int y, size_t w, size_t h)
EAPI Eina_Inlist *
eina_quadtree_collide(Eina_QuadTree *q, int x, int y, int w, int h)
{
Eina_Inlist *head = NULL;
Eina_QuadTree_Item *current;
Eina_QuadTree_Item *p = NULL;
Eina_Rectangle canvas;
Eina_Rectangle target;
Eina_Array_Iterator it;
unsigned int i;
EINA_MAGIC_CHECK_QUADTREE(q);
EINA_MAGIC_CHECK_QUADTREE(q, NULL);
/* Now we need the tree to be up to date, so it's time */
if (q->resize) /* Full rebuild needed ! */
@ -764,15 +771,40 @@ eina_quadtree_collide(Eina_Array *result,
EINA_FALSE, &canvas);
}
EINA_RECTANGLE_SET(&target, x, y, w, h);
if (q->target.x != x
|| q->target.y != y
|| q->target.w != w
|| q->target.h != h)
{
DBG("new target");
EINA_RECTANGLE_SET(&q->target, x, y, w, h);
q->lost = EINA_TRUE;
}
DBG("colliding content");
head = _eina_quadtree_collide(NULL, q->root,
EINA_FALSE, &canvas,
&target);
if (q->lost)
{
DBG("computing collide");
q->cached = _eina_quadtree_collide(NULL, q->root,
EINA_FALSE, &canvas,
&q->target);
}
EINA_INLIST_FOREACH(head, current)
eina_array_push(result, current->object);
return q->cached;
}
EAPI void *
eina_quadtree_object(Eina_Inlist *item)
{
Eina_QuadTree_Item *qi;
if (!item) return NULL;
qi = EINA_INLIST_CONTAINER_GET(item, Eina_QuadTree_Item);
if (!qi) return NULL;
EINA_MAGIC_CHECK_QUADTREE_ITEM(qi, NULL);
return (void*) qi->object;
}
EAPI void
@ -789,6 +821,14 @@ eina_quadtree_resize(Eina_QuadTree *q, size_t w, size_t h)
q->geom.h = h;
}
EAPI void
eina_quadtree_cycle(Eina_QuadTree *q)
{
EINA_MAGIC_CHECK_QUADTREE(q);
q->index = 0;
}
Eina_Bool
eina_quadtree_init(void)
{

View File

@ -35,13 +35,13 @@ struct _Eina_Benchmark_Case
};
static const Eina_Benchmark_Case etc[] = {
{ "Hash", eina_bench_hash },
{ "Array vs List vs Inlist", eina_bench_array },
{ "Stringshare", eina_bench_stringshare },
{ "Convert", eina_bench_convert },
{ "Sort", eina_bench_sort },
{ "Mempool", eina_bench_mempool },
{ "Rectangle_Pool", eina_bench_rectangle_pool },
/* { "Hash", eina_bench_hash }, */
/* { "Array vs List vs Inlist", eina_bench_array }, */
/* { "Stringshare", eina_bench_stringshare }, */
/* { "Convert", eina_bench_convert }, */
/* { "Sort", eina_bench_sort }, */
/* { "Mempool", eina_bench_mempool }, */
/* { "Rectangle_Pool", eina_bench_rectangle_pool }, */
{ "Render Loop", eina_bench_quadtree },
{ NULL, NULL }
};

View File

@ -159,7 +159,7 @@ static void
eina_bench_quadtree_render_loop(int request)
{
Eina_List *objects = NULL;
Eina_Array *possibility;
Eina_Inlist *possibility;
Eina_Bench_Quad *b;
Eina_QuadTree *q;
Eina_Mempool *mp;
@ -189,15 +189,11 @@ eina_bench_quadtree_render_loop(int request)
objects = eina_list_append(objects, b);
}
possibility = eina_array_new(64);
for (j = 0; j < 100; ++j)
{
Eina_Bench_Quad *collide;
Eina_List *changed = NULL;
Eina_List *collided = NULL;
Eina_Array_Iterator it;
unsigned int k;
/* Delete 25% of all objects */
i = request * 25 / 100;
@ -233,15 +229,20 @@ eina_bench_quadtree_render_loop(int request)
(rand() * HEIGHT) / RAND_MAX,
(rand() * WIDTH / 4) / RAND_MAX,
(rand() * HEIGHT / 4) / RAND_MAX);
eina_quadtree_collide(possibility, q,
collide->r.x, collide->r.y,
collide->r.w, collide->r.h);
EINA_ARRAY_ITER_NEXT(possibility, k, b, it)
if (eina_rectangles_intersect(&b->r, &collide->r))
collided = eina_list_append(collided, b);
possibility = eina_quadtree_collide(q,
collide->r.x, collide->r.y,
collide->r.w, collide->r.h);
while (possibility)
{
b = eina_quadtree_object(possibility);
possibility = possibility->next;
if (eina_rectangles_intersect(&b->r, &collide->r))
collided = eina_list_append(collided, b);
}
collided = eina_list_free(collided);
eina_mempool_free(mp, collide);
eina_array_clean(possibility);
/* Modify 50% of all objects */
i = request * 50 / 100;
@ -265,12 +266,16 @@ eina_bench_quadtree_render_loop(int request)
object with all intersecting object */
EINA_LIST_FREE(changed, b)
{
eina_quadtree_collide(possibility, q,
b->r.x, b->r.y, b->r.w, b->r.h);
EINA_ARRAY_ITER_NEXT(possibility, k, collide, it)
if (collide != b && eina_rectangles_intersect(&b->r, &collide->r))
collided = eina_list_append(collided, collide);
eina_array_clean(possibility);
possibility = eina_quadtree_collide(q,
b->r.x, b->r.y, b->r.w, b->r.h);
while (possibility)
{
collide = eina_quadtree_object(possibility);
possibility = possibility->next;
if (collide != b && eina_rectangles_intersect(&b->r, &collide->r))
collided = eina_list_append(collided, collide);
}
collided = eina_list_append(collided, b);
}

View File

@ -79,10 +79,9 @@ START_TEST(eina_quadtree_collision)
int hidden[] = { 4, 5, 6, 8, 10 };
int show[] = { 0, 1, 2 };
Eina_QuadTree *q;
Eina_Array *result;
Eina_Inlist *head;
Eina_Rectangle *r;
Eina_Array_Iterator it;
unsigned int j;
int count;
int i;
fail_if(!eina_init());
@ -100,52 +99,76 @@ START_TEST(eina_quadtree_collision)
fail_if(!eina_quadtree_show(objects[i].item));
}
result = eina_array_new(16);
fail_if(!result);
eina_quadtree_resize(q, 640, 480);
for (i = 0; tests[i].count != -1; ++i)
{
eina_quadtree_collide(result, q,
tests[i].r.x, tests[i].r.y, tests[i].r.w, tests[i].r.h);
fail_if(eina_array_count_get(result) != (unsigned int) tests[i].count);
head = eina_quadtree_collide(q,
tests[i].r.x, tests[i].r.y,
tests[i].r.w, tests[i].r.h);
EINA_ARRAY_ITER_NEXT(result, j, r, it)
count = 0;
while (head)
{
int k;
r = eina_quadtree_object(head);
for (k = 0; k < tests[i].count; ++k)
{
if (&objects[tests[i].result[k]].r == r)
break;
}
fail_if(k == tests[i].count);
}
eina_array_clean(result);
head = head->next;
count++;
}
fail_if(count != tests[i].count);
}
for (j = 0; j < sizeof (hidden) / sizeof (int); ++j)
eina_quadtree_hide(objects[hidden[j]].item);
for (j = 0; j < sizeof (show) / sizeof (int); ++j)
eina_quadtree_show(objects[show[j]].item);
for (i = 0; i < (int) (sizeof (hidden) / sizeof (int)); ++i)
eina_quadtree_hide(objects[hidden[i]].item);
for (i = 0; i < (int) (sizeof (show) / sizeof (int)); ++i)
eina_quadtree_show(objects[show[i]].item);
eina_quadtree_collide(result, q,
tests[1].r.x, tests[1].r.y, tests[1].r.w, tests[1].r.h);
fail_if(eina_array_count_get(result) != 3);
head = eina_quadtree_collide(q,
tests[1].r.x, tests[1].r.y,
tests[1].r.w, tests[1].r.h);
EINA_ARRAY_ITER_NEXT(result, j, r, it)
fail_if(r != &objects[tests[1].result[show[j]]].r);
count = 0;
while (head)
{
r = eina_quadtree_object(head);
eina_array_clean(result);
fail_if(r != &objects[tests[1].result[show[count]]].r);
head = head->next;
count++;
}
fail_if(count != 3);
eina_quadtree_cycle(q);
eina_quadtree_show(objects[4].item);
eina_quadtree_show(objects[5].item);
eina_quadtree_del(objects[5].item);
eina_quadtree_change(objects[10].item);
eina_quadtree_collide(result, q,
tests[0].r.x, tests[0].r.y, tests[0].r.w, tests[0].r.h);
fail_if(eina_array_count_get(result) != 1);
eina_quadtree_resize(q, 641, 480);
head = eina_quadtree_collide(q,
tests[0].r.x, tests[0].r.y,
tests[0].r.w, tests[0].r.h);
count = 0;
while (head)
{
r = eina_quadtree_object(head);
head = head->next;
count++;
}
fail_if(count != 1);
eina_quadtree_free(q);