예제 #1
0
/**
 * Test which verifies that guac_common_rect_extend() expands the given
 * rectangle as necessary to contain at least the given bounds.
 */
void test_rect__extend() {

    guac_common_rect max;
    guac_common_rect rect;

    guac_common_rect_init(&rect, 10, 10, 90, 90);
    guac_common_rect_init(&max, 0, 0, 100, 100);
    guac_common_rect_extend(&rect, &max);
    CU_ASSERT_EQUAL(0, rect.x);
    CU_ASSERT_EQUAL(0, rect.y);
    CU_ASSERT_EQUAL(100, rect.width);
    CU_ASSERT_EQUAL(100, rect.height);

}
void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max) {

    /* Calculate extents of existing dirty rect */
    int left   = rect->x;
    int top    = rect->y;
    int right  = left + rect->width;
    int bottom = top  + rect->height;

    /* Calculate missing extents of given new rect */
    int max_left   = max->x;
    int max_top    = max->y;
    int max_right  = max_left + max->width;
    int max_bottom = max_top  + max->height;

    /* Update maximums */
    if (max_left   > left)   left   = max_left;
    if (max_top    > top)    top    = max_top;
    if (max_right  < right)  right  = max_right;
    if (max_bottom < bottom) bottom = max_bottom;

    /* Commit rect */
    guac_common_rect_init(rect, left, top, right - left, bottom - top);

}
void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min) {

    /* Calculate extents of existing dirty rect */
    int left   = rect->x;
    int top    = rect->y;
    int right  = left + rect->width;
    int bottom = top  + rect->height;

    /* Calculate missing extents of given new rect */
    int min_left   = min->x;
    int min_top    = min->y;
    int min_right  = min_left + min->width;
    int min_bottom = min_top  + min->height;

    /* Update minimums */
    if (min_left   < left)   left   = min_left;
    if (min_top    < top)    top    = min_top;
    if (min_right  > right)  right  = min_right;
    if (min_bottom > bottom) bottom = min_bottom;

    /* Commit rect */
    guac_common_rect_init(rect, left, top, right - left, bottom - top);

}
int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect,
                                    const guac_common_rect* max_rect) {

    /* Invalid cell_size received */
    if (cell_size <= 0)
        return -1;

    /* Nothing to do */
    if (cell_size == 1)
        return 0;

    /* Calculate how much the rectangle must be adjusted to fit within the
     * given cell size. */
    int dw = cell_size - rect->width % cell_size;
    int dh = cell_size - rect->height % cell_size;

    int dx = dw / 2;
    int dy = dh / 2;

    /* Set initial extents of adjusted rectangle. */
    int top = rect->y - dy;
    int left = rect->x - dx;
    int bottom = top + rect->height + dh;
    int right = left + rect->width + dw;

    /* The max rectangle */
    int max_left   = max_rect->x;
    int max_top    = max_rect->y;
    int max_right  = max_left + max_rect->width;
    int max_bottom = max_top  + max_rect->height;

    /* If the adjusted rectangle has sides beyond the max rectangle, or is larger
     * in any direction; shift or adjust the rectangle while trying to fit in
     * the grid */

    /* Adjust left/right */
    if (right > max_right) {

        /* shift to left */
        dw = right - max_right;
        right -= dw;
        left -= dw;

        /* clamp left if too far */
        if (left < max_left) {
            left = max_left;
        }
    }
    else if (left < max_left) {

        /* shift to right */
        dw = max_left - left;
        left += dw;
        right += dw;

        /* clamp right if too far */
        if (right > max_right) {
            right = max_right;
        }
    }

    /* Adjust top/bottom */
    if (bottom > max_bottom) {

        /* shift up */
        dh = bottom - max_bottom;
        bottom -= dh;
        top -= dh;

        /* clamp top if too far */
        if (top < max_top) {
            top = max_top;
        }
    }
    else if (top < max_top) {

        /* shift down */
        dh = max_top - top;
        top += dh;
        bottom += dh;

        /* clamp bottom if too far */
        if (bottom > max_bottom) {
            bottom = max_bottom;
        }
    }

    /* Commit rect */
    guac_common_rect_init(rect, left, top, right - left, bottom - top);

    return 0;

}
int guac_common_rect_clip_and_split(guac_common_rect* rect,
        const guac_common_rect* hole, guac_common_rect* split_rect) {

    /* Only continue if the rectangles intersects */
    if (!guac_common_rect_intersects(rect, hole))
        return 0;

    int top, left, bottom, right;

    /* Clip and split top */
    if (rect->y < hole->y) {
        top = rect->y;
        left = rect->x;
        bottom = hole->y;
        right = rect->x + rect->width;
        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);

        /* Re-initialize original rect */
        top = hole->y;
        bottom = rect->y + rect->height;
        guac_common_rect_init(rect, left, top, right - left, bottom - top);

        return 1;
    }

    /* Clip and split left */
    else if (rect->x < hole->x) {
        top = rect->y;
        left = rect->x;
        bottom = rect->y + rect->height;
        right = hole->x;
        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);

        /* Re-initialize original rect */
        left = hole->x;
        right = rect->x + rect->width;
        guac_common_rect_init(rect, left, top, right - left, bottom - top);

        return 1;
    }

    /* Clip and split bottom */
    else if (rect->y + rect->height > hole->y + hole->height) {
        top = hole->y + hole->height;
        left = rect->x;
        bottom = rect->y + rect->height;
        right = rect->x + rect->width;
        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);

        /* Re-initialize original rect */
        top = rect->y;
        bottom = hole->y + hole->height;
        guac_common_rect_init(rect, left, top, right - left, bottom - top);

        return 1;
    }

    /* Clip and split right */
    else if (rect->x + rect->width > hole->x + hole->width) {
        top = rect->y;
        left = hole->x + hole->width;
        bottom = rect->y + rect->height;
        right = rect->x + rect->width;
        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);

        /* Re-initialize original rect */
        left = rect->x;
        right = hole->x + hole->width;
        guac_common_rect_init(rect, left, top, right - left, bottom - top);

        return 1;
    }

    return 0;
}
예제 #6
0
void test_guac_rect() {

    guac_common_rect max;

    /*
     *  Test init method
     */
    guac_common_rect_init(&max, 0, 0, 100, 100);
    CU_ASSERT_EQUAL(0, max.x);
    CU_ASSERT_EQUAL(0, max.y);
    CU_ASSERT_EQUAL(100, max.width);
    CU_ASSERT_EQUAL(100, max.height);

    /*
     * Test constrain method
     */
    guac_common_rect rect;
    guac_common_rect_init(&rect, -10, -10, 110, 110);
    guac_common_rect_init(&max, 0, 0, 100, 100);
    guac_common_rect_constrain(&rect, &max);
    CU_ASSERT_EQUAL(0, rect.x);
    CU_ASSERT_EQUAL(0, rect.y);
    CU_ASSERT_EQUAL(100, rect.width);
    CU_ASSERT_EQUAL(100, rect.height);

    /*
     * Test extend method
     */
    guac_common_rect_init(&rect, 10, 10, 90, 90);
    guac_common_rect_init(&max, 0, 0, 100, 100);
    guac_common_rect_extend(&rect, &max);
    CU_ASSERT_EQUAL(0, rect.x);
    CU_ASSERT_EQUAL(0, rect.y);
    CU_ASSERT_EQUAL(100, rect.width);
    CU_ASSERT_EQUAL(100, rect.height);

    /*
     * Test adjust method
     */
    int cell_size = 16;

    /* Simple adjustment */
    guac_common_rect_init(&rect, 0, 0, 25, 25);
    guac_common_rect_init(&max, 0, 0, 100, 100);
    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
    CU_ASSERT_EQUAL(0, rect.x);
    CU_ASSERT_EQUAL(0, rect.y);
    CU_ASSERT_EQUAL(32, rect.width);
    CU_ASSERT_EQUAL(32, rect.height);

    /* Adjustment with moving of rect */
    guac_common_rect_init(&rect, 75, 75, 25, 25);
    guac_common_rect_init(&max, 0, 0, 100, 100);
    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
    CU_ASSERT_EQUAL(max.width - 32, rect.x);
    CU_ASSERT_EQUAL(max.height - 32, rect.y);
    CU_ASSERT_EQUAL(32, rect.width);
    CU_ASSERT_EQUAL(32, rect.height);

    guac_common_rect_init(&rect, -5, -5, 25, 25);
    guac_common_rect_init(&max, 0, 0, 100, 100);
    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
    CU_ASSERT_EQUAL(0, rect.x);
    CU_ASSERT_EQUAL(0, rect.y);
    CU_ASSERT_EQUAL(32, rect.width);
    CU_ASSERT_EQUAL(32, rect.height);

    /* Adjustment with moving and clamping of rect */
    guac_common_rect_init(&rect, 0, 0, 25, 15);
    guac_common_rect_init(&max, 0, 5, 32, 15);
    guac_common_rect_expand_to_grid(cell_size, &rect, &max);
    CU_ASSERT_EQUAL(max.x, rect.x);
    CU_ASSERT_EQUAL(max.y, rect.y);
    CU_ASSERT_EQUAL(max.width, rect.width);
    CU_ASSERT_EQUAL(max.height, rect.height);

    /*
     *  Rectangle intersection tests
     */
    guac_common_rect min;
    guac_common_rect_init(&min, 10, 10, 10, 10);

    /* Rectangle intersection - empty
     * rectangle is outside */
    guac_common_rect_init(&rect, 25, 25, 5, 5);
    int res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(0, res);

    /* Rectangle intersection - complete
     * rectangle is completely inside */
    guac_common_rect_init(&rect, 11, 11, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(2, res);

    /* Rectangle intersection - partial
     * rectangle intersects UL */
    guac_common_rect_init(&rect, 8, 8, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(1, res);

    /* Rectangle intersection - partial
     * rectangle intersects LR */
    guac_common_rect_init(&rect, 18, 18, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(1, res);

    /* Rectangle intersection - complete
     * rect intersects along UL but inside */
    guac_common_rect_init(&rect, 10, 10, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(2, res);

    /* Rectangle intersection - partial
     * rectangle intersects along L but outside */
    guac_common_rect_init(&rect, 5, 10, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(1, res);

    /* Rectangle intersection - complete
     * rectangle intersects along LR but rest is inside */
    guac_common_rect_init(&rect, 15, 15, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(2, res);

    /* Rectangle intersection - partial
     * rectangle intersects along R but rest is outside */
    guac_common_rect_init(&rect, 20, 10, 5, 5);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(1, res);

    /* Rectangle intersection - partial
     * rectangle encloses min; which is a partial intersection */
    guac_common_rect_init(&rect, 5, 5, 20, 20);
    res = guac_common_rect_intersects(&rect, &min);
    CU_ASSERT_EQUAL(1, res);

    /*
     * Basic test of clip and split method
     */
    guac_common_rect_init(&min, 10, 10, 10, 10);
    guac_common_rect cut;

    /* Clip top */
    guac_common_rect_init(&rect, 10, 5, 10, 10);
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(10, cut.x);
    CU_ASSERT_EQUAL(5, cut.y);
    CU_ASSERT_EQUAL(10, cut.width);
    CU_ASSERT_EQUAL(5, cut.height);

    CU_ASSERT_EQUAL(10, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(10, rect.width);
    CU_ASSERT_EQUAL(5, rect.height);

    /* Clip bottom */
    guac_common_rect_init(&rect, 10, 15, 10, 10);
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(10, cut.x);
    CU_ASSERT_EQUAL(20, cut.y);
    CU_ASSERT_EQUAL(10, cut.width);
    CU_ASSERT_EQUAL(5, cut.height);

    CU_ASSERT_EQUAL(10, rect.x);
    CU_ASSERT_EQUAL(15, rect.y);
    CU_ASSERT_EQUAL(10, rect.width);
    CU_ASSERT_EQUAL(5, rect.height);

    /* Clip left */
    guac_common_rect_init(&rect, 5, 10, 10, 10);
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(5, cut.x);
    CU_ASSERT_EQUAL(10, cut.y);
    CU_ASSERT_EQUAL(5, cut.width);
    CU_ASSERT_EQUAL(10, cut.height);

    CU_ASSERT_EQUAL(10, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(5, rect.width);
    CU_ASSERT_EQUAL(10, rect.height);

    /* Clip right */
    guac_common_rect_init(&rect, 15, 10, 10, 10);
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(20, cut.x);
    CU_ASSERT_EQUAL(10, cut.y);
    CU_ASSERT_EQUAL(5, cut.width);
    CU_ASSERT_EQUAL(10, cut.height);

    CU_ASSERT_EQUAL(15, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(5, rect.width);
    CU_ASSERT_EQUAL(10, rect.height);

    /*
     * Test a rectangle which completely covers the hole.
     * Clip and split until done.
     */
    guac_common_rect_init(&rect, 5, 5, 20, 20);

    /* Clip top */
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(5, cut.x);
    CU_ASSERT_EQUAL(5, cut.y);
    CU_ASSERT_EQUAL(20, cut.width);
    CU_ASSERT_EQUAL(5, cut.height);

    CU_ASSERT_EQUAL(5, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(20, rect.width);
    CU_ASSERT_EQUAL(15, rect.height);

    /* Clip left */
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(5, cut.x);
    CU_ASSERT_EQUAL(10, cut.y);
    CU_ASSERT_EQUAL(5, cut.width);
    CU_ASSERT_EQUAL(15, cut.height);

    CU_ASSERT_EQUAL(10, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(15, rect.width);
    CU_ASSERT_EQUAL(15, rect.height);

    /* Clip bottom */
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(1, res);
    CU_ASSERT_EQUAL(10, cut.x);
    CU_ASSERT_EQUAL(20, cut.y);
    CU_ASSERT_EQUAL(15, cut.width);
    CU_ASSERT_EQUAL(5, cut.height);

    CU_ASSERT_EQUAL(10, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(15, rect.width);
    CU_ASSERT_EQUAL(10, rect.height);

    /* Clip right */
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(20, cut.x);
    CU_ASSERT_EQUAL(10, cut.y);
    CU_ASSERT_EQUAL(5, cut.width);
    CU_ASSERT_EQUAL(10, cut.height);

    CU_ASSERT_EQUAL(10, rect.x);
    CU_ASSERT_EQUAL(10, rect.y);
    CU_ASSERT_EQUAL(10, rect.width);
    CU_ASSERT_EQUAL(10, rect.height);

    /* Make sure nothing is left to do */
    res = guac_common_rect_clip_and_split(&rect, &min, &cut);
    CU_ASSERT_EQUAL(0, res);

}