From 61cecf1f3f68f5850c58c3abdb4a37a1c158cc10 Mon Sep 17 00:00:00 2001 From: MinJeong Kim Date: Wed, 28 May 2014 16:34:05 +0900 Subject: [PATCH] eina-tiler:add union, subtract, intersection, equal apis for tilers Summary: Support union, subtract, intersection, equal(comparison) between tilers. @feature Test Plan: Test with added test case(src/tests/eina/eina_test_tiler.c) and the example(src/examples/eina/eina_tiler_02.c) Reviewers: gwanglim, devilhorns, raster, zmike, cedric CC: cedric Differential Revision: https://phab.enlightenment.org/D880 --- src/examples/eina/eina_tiler_02.c | 354 ++++++++++++++++++++++++++++++++++++++ src/lib/eina/eina_tiler.c | 206 ++++++++++++++++++++++ src/lib/eina/eina_tiler.h | 49 ++++++ src/tests/eina/eina_test_tiler.c | 107 ++++++++++++ 4 files changed, 716 insertions(+) create mode 100644 src/examples/eina/eina_tiler_02.c diff --git a/src/examples/eina/eina_tiler_02.c b/src/examples/eina/eina_tiler_02.c new file mode 100644 index 0000000..2e80aaa --- /dev/null +++ b/src/examples/eina/eina_tiler_02.c @@ -0,0 +1,354 @@ +//Compile with: +//gcc eina_tiler_02.c -o eina_tiler_02 `pkg-config --cflags --libs ecore-evas ecore evas eina` + +#include +#include +#include +#include + +#define WIN_W (810) +#define WIN_H (280) + +#define TILER1_X (30) +#define TILER1_Y (30) +#define TILER2_X (530) +#define TILER2_Y (30) +#define TILER_W (250) +#define TILER_H (250) +#define RESULT_X (280) +#define RESULT_Y (30) + +static Eina_Tiler *tiler1, *tiler2; +static Eina_List *t1_objs, *t2_objs, *tiler_objs; +static Evas *evas; +static Evas_Object *bg; + +static unsigned int cur_method; +typedef enum { + METHOD_UNION = 0, + METHOD_SUBTRACT, + METHOD_INTERSECTION, +}Current_Method; + +static unsigned int rect_idx =0, rect_count = 4; +static const Eina_Rectangle + rects[4][2][2] = { + {{{40, 0, 80, 250}}, + {{0, 150, 250, 70}, {0, 20, 250, 70}}}, + + {{{20, 20, 65, 150}, {135, 80, 65, 150}}, + {{20, 80, 65, 150}, {135, 20, 65, 150}}}, + + {{{20, 20, 210, 210}}, + {{80, 80, 90, 90}}}, + + {{{0, 0, 150, 90}, {180, 180, 70, 70}}, + {{70, 70, 120, 120}}} +}; + +static const char* + Methods[3] = { + "UNION 1+2", + "SUBTRACT 1-2", + "INTERSECTION 1&2" +}; + +static unsigned int tile_idx =0, tile_count = 5; +static const unsigned int + tilesize[5] = { + 32, + 16, + 8, + 4, + 1 +}; + +static const char commands[] = \ + "commands are:\n" + "\tn - next arrangement \n" + "\tu - get union\n" + "\ts - get subtract\n" + "\ti - get intersection\n" + "\tt - chage tile size ([32], 16, 8, 4) \n" + "\tEsc - Exit\n"; + + +static Evas_Object * +add_text(const char *text, int x, int y, int w) +{ + Evas_Object *o = evas_object_text_add(evas); + evas_object_color_set(o, 0, 0, 0, 255); + evas_object_move(o, x, y); + evas_object_text_font_set(o, "Sans", 20); + evas_object_text_text_set(o, text); + evas_object_show(o); + + return o; +} + +void tiler_calc() +{ + Eina_Tiler *tiler; + Eina_Iterator *itr; + Evas_Object *o; + Eina_Rectangle *rect; + int i = 0; + + /* clear evas rectangles */ + if (tiler_objs) + { + EINA_LIST_FREE(tiler_objs, o) + { + evas_object_hide(o); + evas_object_del(o); + } + } + + tiler = eina_tiler_new(TILER_W, TILER_H); + eina_tiler_tile_size_set(tiler, tilesize[tile_idx], tilesize[tile_idx]); + + /* calculate with tiler1 and tiler2 */ + switch(cur_method) + { + case METHOD_UNION: + eina_tiler_union(tiler, tiler1); + eina_tiler_union(tiler, tiler2); + break; + case METHOD_SUBTRACT: + eina_tiler_union(tiler, tiler1); + eina_tiler_subtract(tiler, tiler2); + break; + case METHOD_INTERSECTION: + tiler = eina_tiler_intersection(tiler1, tiler2); + break; + } + + if (tiler) + { + /* draw rects of result tiler */ + itr = eina_tiler_iterator_new(tiler); + EINA_ITERATOR_FOREACH(itr, rect) + { + fprintf(stdout, "Result Rect [%d] (%d, %d) (%d x %d)\n", i++, rect->x, rect->y, rect->w, rect->h); + + o = evas_object_rectangle_add(evas); + evas_object_color_set(o, 0, 255, 0, 255); + evas_object_resize(o, rect->w, rect->h); + evas_object_move(o, RESULT_X + rect->x, RESULT_Y + rect->y); + evas_object_show(o); + tiler_objs = eina_list_append(tiler_objs, o); + } + eina_iterator_free(itr); + + o = add_text(Methods[cur_method], RESULT_X, 0, TILER_W); + tiler_objs = eina_list_append(tiler_objs, o); + eina_tiler_free(tiler); + } +} + +void rect_update() +{ + Evas_Object *o; + Eina_Rectangle *rect; + Eina_Iterator *itr; + int i = 0; + + if (t1_objs) + { + EINA_LIST_FREE(t1_objs, o) + { + evas_object_hide(o); + evas_object_del(o); + } + } + if (t2_objs) + { + EINA_LIST_FREE(t2_objs, o) + { + evas_object_hide(o); + evas_object_del(o); + } + } + + eina_tiler_clear(tiler1); + eina_tiler_clear(tiler2); + + eina_tiler_tile_size_set(tiler1, tilesize[tile_idx], tilesize[tile_idx]); + eina_tiler_tile_size_set(tiler2, tilesize[tile_idx], tilesize[tile_idx]); + + for (i = 0; i < 2; i ++) + { + if (rects[rect_idx][0][i].w > 0 && rects[rect_idx][0][i].w > 0) + eina_tiler_rect_add(tiler1, &rects[rect_idx][0][i]); + if (rects[rect_idx][1][i].w > 0 && rects[rect_idx][1][i].w > 0) + eina_tiler_rect_add(tiler2, &rects[rect_idx][1][i]); + } + + /* draw rects of tiler1 */ + itr = eina_tiler_iterator_new(tiler1); + EINA_ITERATOR_FOREACH(itr, rect) + { + o = evas_object_rectangle_add(evas); + evas_object_color_set(o, 255, 0, 0, 255); + evas_object_resize(o, rect->w, rect->h); + evas_object_move(o, TILER1_X + rect->x, TILER1_Y + rect->y); + evas_object_show(o); + t1_objs = eina_list_append(t1_objs, o); + } + eina_iterator_free(itr); + + /* draw rects of tiler2 */ + itr = eina_tiler_iterator_new(tiler2); + EINA_ITERATOR_FOREACH(itr, rect) + { + o = evas_object_rectangle_add(evas); + evas_object_color_set(o, 0, 0, 255, 255); + evas_object_resize(o, rect->w, rect->h); + evas_object_move(o, TILER2_X + rect->x, TILER2_Y + rect->y); + evas_object_show(o); + t2_objs = eina_list_append(t2_objs, o); + } + eina_iterator_free(itr); + + tiler_calc(); +} + +static void +_on_key_down(void *data, + Evas *evas EINA_UNUSED, + Evas_Object *o EINA_UNUSED, + void *einfo) +{ + Evas_Event_Key_Down *ev; + int x,y; + + ev = (Evas_Event_Key_Down *)einfo; + + if(strcmp(ev->key,"Escape") == 0) + { + ecore_main_loop_quit(); + } + else if(strcmp(ev->key, "u") == 0) + { + if (cur_method == METHOD_UNION) + return; + + cur_method = METHOD_UNION; + } + else if(strcmp(ev->key, "s") == 0) + { + if (cur_method == METHOD_SUBTRACT) + return; + + cur_method = METHOD_SUBTRACT; + } + else if(strcmp(ev->key, "i") == 0) + { + if (cur_method == METHOD_INTERSECTION) + return; + + cur_method = METHOD_INTERSECTION; + } + else if(strcmp(ev->key, "t") == 0) + { + /* change tiler tile size */ + tile_idx ++; + tile_idx %= tile_count; + fprintf(stdout, "Tiler Size : %d\n", tilesize[tile_idx]); + + rect_update(); + return; + } + else if(strcmp(ev->key, "n") == 0) + { + /* change arrangement of tilers's rects */ + rect_idx ++; + rect_idx %= rect_count; + rect_update(); + return; + } + else + { + fprintf(stdout, "Key %s not supported.\nCommands:%s", ev->key, commands); + return; + } + + tiler_calc(); +} + +int +main(int argc, char *argv[]) +{ + Ecore_Evas *ee; + Evas_Object *o; + int i; + Eina_Rectangle *rect; + Eina_Iterator *itr; + + fprintf(stdout, "Usage.\nCommands:%s", commands); + + ecore_evas_init(); + ecore_init(); + evas_init(); + eina_init(); + + ee = ecore_evas_new(NULL, 0, 0, WIN_W, WIN_H, NULL); + if (!ee) + { + fputs("ERROR: Could not create window. Check ecore-evas install.\n", + stderr); + goto end; + } + + evas = ecore_evas_get(ee); + + /* window bg */ + o = evas_object_rectangle_add(evas); + evas_object_color_set(o, 255, 255, 255, 255); + evas_object_resize(o, WIN_W, WIN_H); + evas_object_show(o); + evas_object_focus_set(o, EINA_TRUE); + bg = o; + + /* tiler1 bg */ + o = evas_object_rectangle_add(evas); + evas_object_color_set(o, 0, 0, 0, 255); + evas_object_resize(o, TILER_W, TILER_H); + evas_object_move(o, TILER1_X, TILER1_Y); + evas_object_show(o); + + /* tiler2 bg */ + o = evas_object_rectangle_add(evas); + evas_object_color_set(o, 0, 0, 0, 255); + evas_object_resize(o, TILER_W, TILER_H); + evas_object_move(o, TILER2_X, TILER2_Y); + evas_object_show(o); + + add_text("Tiler1", TILER1_X, 0, TILER_W); + add_text("Tiler2", TILER2_X, 0, TILER_W); + + tiler1 = eina_tiler_new(TILER_W, TILER_H); + tiler2 = eina_tiler_new(TILER_W, TILER_H); + + rect_update(); + + evas_object_event_callback_add(bg, EVAS_CALLBACK_KEY_DOWN, _on_key_down, NULL); + + ecore_evas_show(ee); + ecore_main_loop_begin(); + + eina_list_free(tiler_objs); + eina_list_free(t1_objs); + eina_list_free(t2_objs); + eina_tiler_free(tiler1); + eina_tiler_free(tiler2); + ecore_evas_free(ee); + + end: + eina_shutdown(); + evas_shutdown(); + ecore_shutdown(); + ecore_evas_shutdown(); + + return 0; +} diff --git a/src/lib/eina/eina_tiler.c b/src/lib/eina/eina_tiler.c index 0301737..275ff7b 100644 --- a/src/lib/eina/eina_tiler.c +++ b/src/lib/eina/eina_tiler.c @@ -1347,6 +1347,212 @@ EAPI Eina_Iterator *eina_tiler_iterator_new(const Eina_Tiler *t) return &it->iterator; } +EAPI Eina_Bool +eina_tiler_union(Eina_Tiler *dst, + Eina_Tiler *src) +{ + Eina_Iterator *itr; + Eina_Rectangle *rect, _rect; + + if ((!src) || (!dst)) + return EINA_FALSE; + + EINA_MAGIC_CHECK_TILER(src, EINA_FALSE); + EINA_MAGIC_CHECK_TILER(dst, EINA_FALSE); + + if ((src->area.w <= 0) || (src->area.h <=0)) + return EINA_FALSE; + + dst->area.w = MAX(src->area.w, dst->area.w); + dst->area.h = MAX(src->area.h, dst->area.h); + + itr = eina_tiler_iterator_new(src); + if (!itr) + return EINA_FALSE; + + EINA_ITERATOR_FOREACH(itr, rect) + { + _rect = *rect; + if (src->rounding) + { + _rect.w -= 1; + _rect.h -= 1; + } + _splitter_rect_add(dst, &_rect); + } + eina_iterator_free(itr); + + if (rect) + dst->last.add = *rect; + + return EINA_TRUE; +} + +EAPI Eina_Bool +eina_tiler_subtract(Eina_Tiler *dst, + Eina_Tiler *src) +{ + Eina_Iterator *itr; + Eina_Rectangle *rect, _rect; + + if ((!src) || (!dst)) + return EINA_FALSE; + + EINA_MAGIC_CHECK_TILER(src, EINA_FALSE); + EINA_MAGIC_CHECK_TILER(dst, EINA_FALSE); + + if ((src->area.w <= 0) || (src->area.h <= 0)) + return EINA_FALSE; + + itr = eina_tiler_iterator_new(src); + if (!itr) + return EINA_FALSE; + + EINA_ITERATOR_FOREACH(itr, rect) + { + _rect = *rect; + if (src->rounding) + { + _rect.w -= 1; + _rect.h -= 1; + } + _splitter_rect_del(dst, &_rect); + } + eina_iterator_free(itr); + + if (rect) + dst->last.del = *rect; + + return EINA_TRUE; +} + +EAPI Eina_Tiler * +eina_tiler_intersection(Eina_Tiler *t1, + Eina_Tiler *t2) +{ + Eina_Tiler *t; + int w, h; + + Eina_Iterator *itr1, *itr2; + Eina_Rectangle rect, *rect1, *rect2; + + EINA_MAGIC_CHECK_TILER(t1, NULL); + EINA_MAGIC_CHECK_TILER(t2, NULL); + + if (!(eina_rectangles_intersect(&t1->area, &t2->area))) + return NULL; + + w = MIN(t1->area.w, t2->area.w); + h = MIN(t1->area.h, t2->area.h); + t = eina_tiler_new(w, h); + + itr1 = eina_tiler_iterator_new(t1); + itr2 = eina_tiler_iterator_new(t2); + + if ((!eina_iterator_next(itr1, (void**)(void*)(&rect1))) && (!rect1)) + return NULL; + if ((!eina_iterator_next(itr2, (void**)(void*)(&rect2))) && (!rect2)) + return NULL; + + while((rect1) && (rect2)) + { + if (eina_rectangles_intersect(rect1, rect2)) + { + rect.x = MAX(rect1->x, rect2->x); + rect.y = MAX(rect1->y, rect2->y); + rect.w = MIN(rect1->x + rect1->w, rect2->x + rect2->w) - rect.x; + rect.h = MIN(rect1->y + rect1->h, rect2->y + rect2->h) - rect.y; + + if ((t1->rounding) || (t2->rounding)) + { + rect.w -= 1; + rect.h -= 1; + } + + _splitter_rect_add(t, &rect); + + t->last.add = rect; + } + + if (rect1->x + rect1->w < rect2->x + rect2->w) + { + if(eina_iterator_next(itr1, (void**)&rect1)) + continue; + } + else if (rect1->x + rect1->w > rect2->x + rect2->w) + { + if (eina_iterator_next(itr2, (void**)&rect2)) + continue; + } + + if (eina_iterator_next(itr1, (void**)&rect1)) + continue; + if (eina_iterator_next(itr2, (void**)&rect2)) + continue; + + break; + } + + eina_iterator_free(itr1); + eina_iterator_free(itr2); + + return t; +} + +EAPI Eina_Bool +eina_tiler_equal(Eina_Tiler *t1, + Eina_Tiler *t2) +{ + Eina_Iterator *itr1, *itr2; + Eina_Rectangle *rect1, *rect2; + Eina_Bool next_t1 = EINA_FALSE, next_t2 = EINA_FALSE; + + EINA_MAGIC_CHECK_TILER(t1, EINA_FALSE); + EINA_MAGIC_CHECK_TILER(t2, EINA_FALSE); + + if (!(eina_rectangles_intersect(&t1->area, &t2->area))) + return EINA_FALSE; + + itr1 = eina_tiler_iterator_new(t1); + itr2 = eina_tiler_iterator_new(t2); + + if ((!eina_iterator_next(itr1, (void**)(void*)(&rect1))) && (!rect1)) + return EINA_FALSE; + if ((!eina_iterator_next(itr2, (void**)(void*)(&rect2))) && (!rect2)) + return EINA_FALSE; + + while((rect1) && (rect2)) + { + if (eina_rectangles_intersect(rect1, rect2)) + { + if ((rect1->x != rect2->x) || + (rect1->y != rect2->y) || + (rect1->w != rect2->w) || + (rect1->h != rect2->h)) + { + return EINA_FALSE; + } + } + else + return EINA_FALSE; + + next_t1 = eina_iterator_next(itr1, (void**)&rect1); + next_t2 = eina_iterator_next(itr2, (void**)&rect2); + + if (next_t1 != next_t2) + return EINA_FALSE; + + if (!next_t1 && !next_t2) + break; + } + + eina_iterator_free(itr1); + eina_iterator_free(itr2); + + return EINA_TRUE; + +} + struct _Eina_Tile_Grid_Slicer_Iterator { Eina_Iterator iterator; diff --git a/src/lib/eina/eina_tiler.h b/src/lib/eina/eina_tiler.h index 3a48383..0f60751 100644 --- a/src/lib/eina/eina_tiler.h +++ b/src/lib/eina/eina_tiler.h @@ -308,6 +308,55 @@ EAPI Eina_Iterator *eina_tiler_iterator_new(const Eina_Tiler *t); * eina_tile_grid_slicer_next() untill it returns #EINA_FALSE. */ EAPI Eina_Iterator *eina_tile_grid_slicer_iterator_new(int x, int y, int w, int h, int tile_w, int tile_h); + +/** + * @brief Gets the union of two tilers. + * + * @param dst The first tiler, will store the result. + * @param src The second tiler. + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * This fuction get the union of tilers @p dst and @p src. + * The result is stored in @p dst. It returns #EINA_TRUE if it succeeds. + */ +EAPI Eina_Bool eina_tiler_union(Eina_Tiler *dst, Eina_Tiler *src); + +/** + * @brief Subtracts two tilers. + * + * @param dst The first tiler, will store the result. + * @param src The second tiler. + * @return #EINA_TRUE on success, #EINA_FALSE otherwise. + * + * This fuction subtracts two tilers @p dst and @p src. + * The result is stored in @p dst. It returns #EINA_TRUE if it succeeds. + */ +EAPI Eina_Bool eina_tiler_subtract(Eina_Tiler *dst, Eina_Tiler *src); + +/** + * @brief Gets the intersection of two tilers. + * + * @param t1 The first tile. + * @param t2 The second tiler. + * @return A pointer of intersection result. @c NULL on failure. + * + * This fuction gest intersection of two tilers @p t1 and @p t2. + * It returns a pointer of result if it succeeds., otherwise returns NULL. + */ +EAPI Eina_Tiler *eina_tiler_intersection(Eina_Tiler *t1, Eina_Tiler *t2); + +/** + * @brief Gets whether two tilers are equal in rects or not. + * + * @param t1 The first tiler. + * @param t2 The second tiler. + * @return #EINA_TRUE is equal, #EINA_FALSE is unequal. + * + * This fuction gets result of comparison for @p t1 and @p t2. + * It returns #EINA_TRUE if tilers are equal. + */ +EAPI Eina_Bool eina_tiler_equal(Eina_Tiler *t1, Eina_Tiler *t2); + /** * @brief Iterates over the tiles set by eina_tile_grid_slicer_setup(). * diff --git a/src/tests/eina/eina_test_tiler.c b/src/tests/eina/eina_test_tiler.c index 2dec168..554dc11 100644 --- a/src/tests/eina/eina_test_tiler.c +++ b/src/tests/eina/eina_test_tiler.c @@ -220,10 +220,117 @@ START_TEST(eina_test_tiler_stable) } END_TEST +START_TEST(eina_test_tiler_calculation) +{ + Eina_Tiler *t1, *t2, *t; + Eina_Iterator *itr; + Eina_Rectangle r1, r2, *rp; + int i = 0; + + eina_init(); + + t1 = eina_tiler_new(500, 500); + fail_if(!t1); + + t2 = eina_tiler_new(500, 500); + fail_if(!t2); + + t = eina_tiler_new(500, 500); + fail_if(!t); + + eina_tiler_tile_size_set(t1, 1, 1); + eina_tiler_tile_size_set(t2, 1, 1); + eina_tiler_tile_size_set(t, 1, 1); + + EINA_RECTANGLE_SET(&r1, 0, 0, 500, 500); + eina_tiler_rect_add(t1, &r1); + + EINA_RECTANGLE_SET(&r2, 100, 100, 300, 300); + eina_tiler_rect_add(t2, &r2); + + fail_if(!eina_tiler_union(t1, t2)); + + itr = eina_tiler_iterator_new(t1); + EINA_ITERATOR_FOREACH(itr, rp) + { + fail_if(rp->w != 500); + fail_if(rp->h != 500); + fail_if(rp->x != 0); + fail_if(rp->y != 0); + ++i; + } + + eina_iterator_free(itr); + eina_tiler_clear(t1); + + fail_if(i != 1); + + eina_tiler_rect_add(t1, &r1); + + fail_if(!eina_tiler_subtract(t1, t2)); + + i = 0; + itr = eina_tiler_iterator_new(t1); + EINA_ITERATOR_FOREACH(itr, rp) + { + fail_if(!eina_rectangles_intersect(&r1, rp)); + fail_if(eina_rectangles_intersect(&r2, rp)); + + fail_if(rp->w <= 0); + fail_if(rp->h <= 0); + fail_if(rp->x < 0 || rp->x + rp->w > 500); + fail_if(rp->y < 0 || rp->y + rp->h > 500); + ++i; + } + + eina_iterator_free(itr); + eina_tiler_clear(t1); + + fail_if(i != 4); + + + eina_tiler_rect_add(t1, &r1); + + t = eina_tiler_intersection(t1, t2); + fail_if(!t); + + i = 0; + itr = eina_tiler_iterator_new(t); + EINA_ITERATOR_FOREACH(itr, rp) + { + fail_if(!eina_rectangles_intersect(&r1, rp)); + fail_if(!eina_rectangles_intersect(&r2, rp)); + + fail_if(rp->w <= 0); + fail_if(rp->h <= 0); + fail_if(rp->x < 0 || rp->x + rp->w > 500); + fail_if(rp->y < 0 || rp->y + rp->h > 500); + ++i; + } + + eina_iterator_free(itr); + eina_tiler_clear(t); + + fail_if(i != 1); + + eina_tiler_rect_add(t, &r1); + + fail_if(!eina_tiler_equal(t, t1)); + fail_if(!eina_tiler_equal(t1, t)); + + eina_tiler_free(t); + eina_tiler_free(t1); + eina_tiler_free(t2); + + eina_shutdown(); +} +END_TEST + void eina_test_tiler(TCase *tc) { tcase_add_test(tc, eina_test_tile_grid_slicer_iterator); tcase_add_test(tc, eina_test_tiler_all); tcase_add_test(tc, eina_test_tiler_stable); + tcase_add_test(tc, eina_test_tiler_calculation); } -- 2.7.4