cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

rect.c (7791B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "config.h"
     21#include "common/rect.h"
     22
     23void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height) {
     24    rect->x      = x;
     25    rect->y      = y;
     26    rect->width  = width;
     27    rect->height = height;
     28}
     29
     30void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min) {
     31
     32    /* Calculate extents of existing dirty rect */
     33    int left   = rect->x;
     34    int top    = rect->y;
     35    int right  = left + rect->width;
     36    int bottom = top  + rect->height;
     37
     38    /* Calculate missing extents of given new rect */
     39    int min_left   = min->x;
     40    int min_top    = min->y;
     41    int min_right  = min_left + min->width;
     42    int min_bottom = min_top  + min->height;
     43
     44    /* Update minimums */
     45    if (min_left   < left)   left   = min_left;
     46    if (min_top    < top)    top    = min_top;
     47    if (min_right  > right)  right  = min_right;
     48    if (min_bottom > bottom) bottom = min_bottom;
     49
     50    /* Commit rect */
     51    guac_common_rect_init(rect, left, top, right - left, bottom - top);
     52
     53}
     54
     55void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max) {
     56
     57    /* Calculate extents of existing dirty rect */
     58    int left   = rect->x;
     59    int top    = rect->y;
     60    int right  = left + rect->width;
     61    int bottom = top  + rect->height;
     62
     63    /* Calculate missing extents of given new rect */
     64    int max_left   = max->x;
     65    int max_top    = max->y;
     66    int max_right  = max_left + max->width;
     67    int max_bottom = max_top  + max->height;
     68
     69    /* Update maximums */
     70    if (max_left   > left)   left   = max_left;
     71    if (max_top    > top)    top    = max_top;
     72    if (max_right  < right)  right  = max_right;
     73    if (max_bottom < bottom) bottom = max_bottom;
     74
     75    /* Commit rect */
     76    guac_common_rect_init(rect, left, top, right - left, bottom - top);
     77
     78}
     79
     80int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect,
     81                                    const guac_common_rect* max_rect) {
     82
     83    /* Invalid cell_size received */
     84    if (cell_size <= 0)
     85        return -1;
     86
     87    /* Nothing to do */
     88    if (cell_size == 1)
     89        return 0;
     90
     91    /* Calculate how much the rectangle must be adjusted to fit within the
     92     * given cell size. */
     93    int dw = cell_size - rect->width % cell_size;
     94    int dh = cell_size - rect->height % cell_size;
     95
     96    int dx = dw / 2;
     97    int dy = dh / 2;
     98
     99    /* Set initial extents of adjusted rectangle. */
    100    int top = rect->y - dy;
    101    int left = rect->x - dx;
    102    int bottom = top + rect->height + dh;
    103    int right = left + rect->width + dw;
    104
    105    /* The max rectangle */
    106    int max_left   = max_rect->x;
    107    int max_top    = max_rect->y;
    108    int max_right  = max_left + max_rect->width;
    109    int max_bottom = max_top  + max_rect->height;
    110
    111    /* If the adjusted rectangle has sides beyond the max rectangle, or is larger
    112     * in any direction; shift or adjust the rectangle while trying to fit in
    113     * the grid */
    114
    115    /* Adjust left/right */
    116    if (right > max_right) {
    117
    118        /* shift to left */
    119        dw = right - max_right;
    120        right -= dw;
    121        left -= dw;
    122
    123        /* clamp left if too far */
    124        if (left < max_left) {
    125            left = max_left;
    126        }
    127    }
    128    else if (left < max_left) {
    129
    130        /* shift to right */
    131        dw = max_left - left;
    132        left += dw;
    133        right += dw;
    134
    135        /* clamp right if too far */
    136        if (right > max_right) {
    137            right = max_right;
    138        }
    139    }
    140
    141    /* Adjust top/bottom */
    142    if (bottom > max_bottom) {
    143
    144        /* shift up */
    145        dh = bottom - max_bottom;
    146        bottom -= dh;
    147        top -= dh;
    148
    149        /* clamp top if too far */
    150        if (top < max_top) {
    151            top = max_top;
    152        }
    153    }
    154    else if (top < max_top) {
    155
    156        /* shift down */
    157        dh = max_top - top;
    158        top += dh;
    159        bottom += dh;
    160
    161        /* clamp bottom if too far */
    162        if (bottom > max_bottom) {
    163            bottom = max_bottom;
    164        }
    165    }
    166
    167    /* Commit rect */
    168    guac_common_rect_init(rect, left, top, right - left, bottom - top);
    169
    170    return 0;
    171
    172}
    173
    174int guac_common_rect_intersects(const guac_common_rect* rect,
    175                                const guac_common_rect* other) {
    176
    177    /* Empty (no intersection) */
    178    if (other->x + other->width < rect->x || rect->x + rect->width < other->x ||
    179        other->y + other->height < rect->y || rect->y + rect->height < other->y) {
    180        return 0;
    181    }
    182    /* Complete */
    183    else if (other->x <= rect->x && (other->x + other->width) >= (rect->x + rect->width) &&
    184        other->y <= rect->y && (other->y + other->height) >= (rect->y + rect->height)) {
    185        return 2;
    186    }
    187    /* Partial intersection */
    188    return 1;
    189
    190}
    191
    192int guac_common_rect_clip_and_split(guac_common_rect* rect,
    193        const guac_common_rect* hole, guac_common_rect* split_rect) {
    194
    195    /* Only continue if the rectangles intersects */
    196    if (!guac_common_rect_intersects(rect, hole))
    197        return 0;
    198
    199    int top, left, bottom, right;
    200
    201    /* Clip and split top */
    202    if (rect->y < hole->y) {
    203        top = rect->y;
    204        left = rect->x;
    205        bottom = hole->y;
    206        right = rect->x + rect->width;
    207        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
    208
    209        /* Re-initialize original rect */
    210        top = hole->y;
    211        bottom = rect->y + rect->height;
    212        guac_common_rect_init(rect, left, top, right - left, bottom - top);
    213
    214        return 1;
    215    }
    216
    217    /* Clip and split left */
    218    else if (rect->x < hole->x) {
    219        top = rect->y;
    220        left = rect->x;
    221        bottom = rect->y + rect->height;
    222        right = hole->x;
    223        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
    224
    225        /* Re-initialize original rect */
    226        left = hole->x;
    227        right = rect->x + rect->width;
    228        guac_common_rect_init(rect, left, top, right - left, bottom - top);
    229
    230        return 1;
    231    }
    232
    233    /* Clip and split bottom */
    234    else if (rect->y + rect->height > hole->y + hole->height) {
    235        top = hole->y + hole->height;
    236        left = rect->x;
    237        bottom = rect->y + rect->height;
    238        right = rect->x + rect->width;
    239        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
    240
    241        /* Re-initialize original rect */
    242        top = rect->y;
    243        bottom = hole->y + hole->height;
    244        guac_common_rect_init(rect, left, top, right - left, bottom - top);
    245
    246        return 1;
    247    }
    248
    249    /* Clip and split right */
    250    else if (rect->x + rect->width > hole->x + hole->width) {
    251        top = rect->y;
    252        left = hole->x + hole->width;
    253        bottom = rect->y + rect->height;
    254        right = rect->x + rect->width;
    255        guac_common_rect_init(split_rect, left, top, right - left, bottom - top);
    256
    257        /* Re-initialize original rect */
    258        left = rect->x;
    259        right = hole->x + hole->width;
    260        guac_common_rect_init(rect, left, top, right - left, bottom - top);
    261
    262        return 1;
    263    }
    264
    265    return 0;
    266}