acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_area.c (13820B)

      1 /**
      2  * @file lv_area.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "../lv_conf_internal.h"
     10 
     11 #include "lv_area.h"
     12 #include "lv_math.h"
     13 
     14 /*********************
     15  *      DEFINES
     16  *********************/
     17 
     18 /**********************
     19  *      TYPEDEFS
     20  **********************/
     21 
     22 /**********************
     23  *  STATIC PROTOTYPES
     24  **********************/
     25 
     26 static bool lv_point_within_circle(const lv_area_t * area, const lv_point_t * p);
     27 
     28 /**********************
     29  *  STATIC VARIABLES
     30  **********************/
     31 
     32 /**********************
     33  *      MACROS
     34  **********************/
     35 
     36 /**********************
     37  *   GLOBAL FUNCTIONS
     38  **********************/
     39 
     40 /**
     41  * Initialize an area
     42  * @param area_p pointer to an area
     43  * @param x1 left coordinate of the area
     44  * @param y1 top coordinate of the area
     45  * @param x2 right coordinate of the area
     46  * @param y2 bottom coordinate of the area
     47  */
     48 void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2)
     49 {
     50     area_p->x1 = x1;
     51     area_p->y1 = y1;
     52     area_p->x2 = x2;
     53     area_p->y2 = y2;
     54 }
     55 
     56 /**
     57  * Set the width of an area
     58  * @param area_p pointer to an area
     59  * @param w the new width of the area (w == 1 makes x1 == x2)
     60  */
     61 void lv_area_set_width(lv_area_t * area_p, lv_coord_t w)
     62 {
     63     area_p->x2 = area_p->x1 + w - 1;
     64 }
     65 
     66 /**
     67  * Set the height of an area
     68  * @param area_p pointer to an area
     69  * @param h the new height of the area (h == 1 makes y1 == y2)
     70  */
     71 void lv_area_set_height(lv_area_t * area_p, lv_coord_t h)
     72 {
     73     area_p->y2 = area_p->y1 + h - 1;
     74 }
     75 
     76 /**
     77  * Set the position of an area (width and height will be kept)
     78  * @param area_p pointer to an area
     79  * @param x the new x coordinate of the area
     80  * @param y the new y coordinate of the area
     81  */
     82 void _lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y)
     83 {
     84     lv_coord_t w = lv_area_get_width(area_p);
     85     lv_coord_t h = lv_area_get_height(area_p);
     86     area_p->x1   = x;
     87     area_p->y1   = y;
     88     lv_area_set_width(area_p, w);
     89     lv_area_set_height(area_p, h);
     90 }
     91 
     92 /**
     93  * Return with area of an area (x * y)
     94  * @param area_p pointer to an area
     95  * @return size of area
     96  */
     97 uint32_t lv_area_get_size(const lv_area_t * area_p)
     98 {
     99     uint32_t size;
    100 
    101     size = (uint32_t)(area_p->x2 - area_p->x1 + 1) * (area_p->y2 - area_p->y1 + 1);
    102 
    103     return size;
    104 }
    105 
    106 void lv_area_increase(lv_area_t * area, lv_coord_t w_extra, lv_coord_t h_extra)
    107 {
    108     area->x1 -= w_extra;
    109     area->x2 += w_extra;
    110     area->y1 -= h_extra;
    111     area->y2 += h_extra;
    112 }
    113 
    114 void lv_area_move(lv_area_t * area, lv_coord_t x_ofs, lv_coord_t y_ofs)
    115 {
    116     area->x1 += x_ofs;
    117     area->x2 += x_ofs;
    118     area->y1 += y_ofs;
    119     area->y2 += y_ofs;
    120 }
    121 
    122 /**
    123  * Get the common parts of two areas
    124  * @param res_p pointer to an area, the result will be stored here
    125  * @param a1_p pointer to the first area
    126  * @param a2_p pointer to the second area
    127  * @return false: the two area has NO common parts, res_p is invalid
    128  */
    129 bool _lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)
    130 {
    131     /*Get the smaller area from 'a1_p' and 'a2_p'*/
    132     res_p->x1 = LV_MAX(a1_p->x1, a2_p->x1);
    133     res_p->y1 = LV_MAX(a1_p->y1, a2_p->y1);
    134     res_p->x2 = LV_MIN(a1_p->x2, a2_p->x2);
    135     res_p->y2 = LV_MIN(a1_p->y2, a2_p->y2);
    136 
    137     /*If x1 or y1 greater than x2 or y2 then the areas union is empty*/
    138     bool union_ok = true;
    139     if((res_p->x1 > res_p->x2) || (res_p->y1 > res_p->y2)) {
    140         union_ok = false;
    141     }
    142 
    143     return union_ok;
    144 }
    145 
    146 /**
    147  * Join two areas into a third which involves the other two
    148  * @param res_p pointer to an area, the result will be stored here
    149  * @param a1_p pointer to the first area
    150  * @param a2_p pointer to the second area
    151  */
    152 void _lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p)
    153 {
    154     a_res_p->x1 = LV_MIN(a1_p->x1, a2_p->x1);
    155     a_res_p->y1 = LV_MIN(a1_p->y1, a2_p->y1);
    156     a_res_p->x2 = LV_MAX(a1_p->x2, a2_p->x2);
    157     a_res_p->y2 = LV_MAX(a1_p->y2, a2_p->y2);
    158 }
    159 
    160 /**
    161  * Check if a point is on an area
    162  * @param a_p pointer to an area
    163  * @param p_p pointer to a point
    164  * @param radius radius of area (e.g. for rounded rectangle)
    165  * @return false:the point is out of the area
    166  */
    167 bool _lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p, lv_coord_t radius)
    168 {
    169     /*First check the basic area*/
    170     bool is_on_rect = false;
    171     if((p_p->x >= a_p->x1 && p_p->x <= a_p->x2) && ((p_p->y >= a_p->y1 && p_p->y <= a_p->y2))) {
    172         is_on_rect = true;
    173     }
    174     if(!is_on_rect)
    175         return false;
    176     /*Now handle potential rounded rectangles*/
    177     if(radius <= 0) {
    178         /*No radius, it is within the rectangle*/
    179         return true;
    180     }
    181     lv_coord_t w = lv_area_get_width(a_p) / 2;
    182     lv_coord_t h = lv_area_get_height(a_p) / 2;
    183     lv_coord_t max_radius = LV_MIN(w, h);
    184     if(radius > max_radius)
    185         radius = max_radius;
    186 
    187     /*Check if it's in one of the corners*/
    188     lv_area_t corner_area;
    189     /*Top left*/
    190     corner_area.x1 = a_p->x1;
    191     corner_area.x2 = a_p->x1 + radius;
    192     corner_area.y1 = a_p->y1;
    193     corner_area.y2 = a_p->y1 + radius;
    194     if(_lv_area_is_point_on(&corner_area, p_p, 0)) {
    195         corner_area.x2 += radius;
    196         corner_area.y2 += radius;
    197         return lv_point_within_circle(&corner_area, p_p);
    198     }
    199     /*Bottom left*/
    200     corner_area.y1 = a_p->y2 - radius;
    201     corner_area.y2 = a_p->y2;
    202     if(_lv_area_is_point_on(&corner_area, p_p, 0)) {
    203         corner_area.x2 += radius;
    204         corner_area.y1 -= radius;
    205         return lv_point_within_circle(&corner_area, p_p);
    206     }
    207     /*Bottom right*/
    208     corner_area.x1 = a_p->x2 - radius;
    209     corner_area.x2 = a_p->x2;
    210     if(_lv_area_is_point_on(&corner_area, p_p, 0)) {
    211         corner_area.x1 -= radius;
    212         corner_area.y1 -= radius;
    213         return lv_point_within_circle(&corner_area, p_p);
    214     }
    215     /*Top right*/
    216     corner_area.y1 = a_p->y1;
    217     corner_area.y2 = a_p->y1 + radius;
    218     if(_lv_area_is_point_on(&corner_area, p_p, 0)) {
    219         corner_area.x1 -= radius;
    220         corner_area.y2 += radius;
    221         return lv_point_within_circle(&corner_area, p_p);
    222     }
    223     /*Not within corners*/
    224     return true;
    225 }
    226 
    227 /**
    228  * Check if two area has common parts
    229  * @param a1_p pointer to an area.
    230  * @param a2_p pointer to an other area
    231  * @return false: a1_p and a2_p has no common parts
    232  */
    233 bool _lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p)
    234 {
    235     if((a1_p->x1 <= a2_p->x2) && (a1_p->x2 >= a2_p->x1) && (a1_p->y1 <= a2_p->y2) && (a1_p->y2 >= a2_p->y1)) {
    236         return true;
    237     }
    238     else {
    239         return false;
    240     }
    241 }
    242 
    243 /**
    244  * Check if an area is fully on an other
    245  * @param ain_p pointer to an area which could be in 'aholder_p'
    246  * @param aholder_p pointer to an area which could involve 'ain_p'
    247  * @param radius radius of `aholder_p` (e.g. for rounded rectangle)
    248  * @return true: `ain_p` is fully inside `aholder_p`
    249  */
    250 bool _lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p, lv_coord_t radius)
    251 {
    252     bool is_in = false;
    253 
    254     if(ain_p->x1 >= aholder_p->x1 && ain_p->y1 >= aholder_p->y1 && ain_p->x2 <= aholder_p->x2 &&
    255        ain_p->y2 <= aholder_p->y2) {
    256         is_in = true;
    257     }
    258 
    259     if(!is_in) return false;
    260     if(radius == 0) return true;
    261 
    262     /*Check if the corner points are inside the radius or not*/
    263     lv_point_t p;
    264 
    265     p.x = ain_p->x1;
    266     p.y = ain_p->y1;
    267     if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false;
    268 
    269     p.x = ain_p->x2;
    270     p.y = ain_p->y1;
    271     if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false;
    272 
    273     p.x = ain_p->x1;
    274     p.y = ain_p->y2;
    275     if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false;
    276 
    277     p.x = ain_p->x2;
    278     p.y = ain_p->y2;
    279     if(_lv_area_is_point_on(aholder_p, &p, radius) == false) return false;
    280 
    281     return true;
    282 }
    283 
    284 /**
    285  * Check if an area is fully out of an other
    286  * @param aout_p pointer to an area which could be in 'aholder_p'
    287  * @param aholder_p pointer to an area which could involve 'ain_p'
    288  * @param radius radius of `aholder_p` (e.g. for rounded rectangle)
    289  * @return true: `aout_p` is fully outside `aholder_p`
    290  */
    291 bool _lv_area_is_out(const lv_area_t * aout_p, const lv_area_t * aholder_p, lv_coord_t radius)
    292 {
    293     if(aout_p->x2 < aholder_p->x1 || aout_p->y2 < aholder_p->y1 || aout_p->x1 > aholder_p->x2 ||
    294        aout_p->y1 > aholder_p->y2) {
    295         return true;
    296     }
    297 
    298     if(radius == 0) return false;
    299 
    300     /*Check if the corner points are outside the radius or not*/
    301     lv_point_t p;
    302 
    303     p.x = aout_p->x1;
    304     p.y = aout_p->y1;
    305     if(_lv_area_is_point_on(aholder_p, &p, radius)) return false;
    306 
    307     p.x = aout_p->x2;
    308     p.y = aout_p->y1;
    309     if(_lv_area_is_point_on(aholder_p, &p, radius)) return false;
    310 
    311     p.x = aout_p->x1;
    312     p.y = aout_p->y2;
    313     if(_lv_area_is_point_on(aholder_p, &p, radius)) return false;
    314 
    315     p.x = aout_p->x2;
    316     p.y = aout_p->y2;
    317     if(_lv_area_is_point_on(aholder_p, &p, radius)) return false;
    318 
    319     return true;
    320 }
    321 
    322 bool _lv_area_is_equal(const lv_area_t * a, const lv_area_t * b)
    323 {
    324     return a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y1 && a->y2 == b->y2;
    325 }
    326 
    327 /**
    328  * Align an area to an other
    329  * @param base an are where the other will be aligned
    330  * @param to_align the area to align
    331  * @param align `LV_ALIGN_...`
    332  * @param res x/y coordinates where `to_align` align area should be placed
    333  */
    334 void lv_area_align(const lv_area_t * base, lv_area_t * to_align, lv_align_t align, lv_coord_t ofs_x, lv_coord_t ofs_y)
    335 {
    336 
    337     lv_coord_t x;
    338     lv_coord_t y;
    339     switch(align) {
    340         case LV_ALIGN_CENTER:
    341             x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2;
    342             y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2;
    343             break;
    344 
    345         case LV_ALIGN_TOP_LEFT:
    346             x = 0;
    347             y = 0;
    348             break;
    349         case LV_ALIGN_TOP_MID:
    350             x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2;
    351             y = 0;
    352             break;
    353 
    354         case LV_ALIGN_TOP_RIGHT:
    355             x = lv_area_get_width(base) - lv_area_get_width(to_align);
    356             y = 0;
    357             break;
    358 
    359         case LV_ALIGN_BOTTOM_LEFT:
    360             x = 0;
    361             y = lv_area_get_height(base) - lv_area_get_height(to_align);
    362             break;
    363         case LV_ALIGN_BOTTOM_MID:
    364             x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2;
    365             y = lv_area_get_height(base) - lv_area_get_height(to_align);
    366             break;
    367 
    368         case LV_ALIGN_BOTTOM_RIGHT:
    369             x = lv_area_get_width(base) - lv_area_get_width(to_align);
    370             y = lv_area_get_height(base) - lv_area_get_height(to_align);
    371             break;
    372 
    373         case LV_ALIGN_LEFT_MID:
    374             x = 0;
    375             y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2;
    376             break;
    377 
    378         case LV_ALIGN_RIGHT_MID:
    379             x = lv_area_get_width(base) - lv_area_get_width(to_align);
    380             y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2;
    381             break;
    382 
    383         case LV_ALIGN_OUT_TOP_LEFT:
    384             x = 0;
    385             y = -lv_area_get_height(to_align);
    386             break;
    387 
    388         case LV_ALIGN_OUT_TOP_MID:
    389             x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2;
    390             y = -lv_area_get_height(to_align);
    391             break;
    392 
    393         case LV_ALIGN_OUT_TOP_RIGHT:
    394             x = lv_area_get_width(base) - lv_area_get_width(to_align);
    395             y = -lv_area_get_height(to_align);
    396             break;
    397 
    398         case LV_ALIGN_OUT_BOTTOM_LEFT:
    399             x = 0;
    400             y = lv_area_get_height(base);
    401             break;
    402 
    403         case LV_ALIGN_OUT_BOTTOM_MID:
    404             x = lv_area_get_width(base) / 2 - lv_area_get_width(to_align) / 2;
    405             y = lv_area_get_height(base);
    406             break;
    407 
    408         case LV_ALIGN_OUT_BOTTOM_RIGHT:
    409             x = lv_area_get_width(base) - lv_area_get_width(to_align);
    410             y = lv_area_get_height(base);
    411             break;
    412 
    413         case LV_ALIGN_OUT_LEFT_TOP:
    414             x = -lv_area_get_width(to_align);
    415             y = 0;
    416             break;
    417 
    418         case LV_ALIGN_OUT_LEFT_MID:
    419             x = -lv_area_get_width(to_align);
    420             y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2;
    421             break;
    422 
    423         case LV_ALIGN_OUT_LEFT_BOTTOM:
    424             x = -lv_area_get_width(to_align);
    425             y = lv_area_get_height(base) - lv_area_get_height(to_align);
    426             break;
    427 
    428         case LV_ALIGN_OUT_RIGHT_TOP:
    429             x = lv_area_get_width(base);
    430             y = 0;
    431             break;
    432 
    433         case LV_ALIGN_OUT_RIGHT_MID:
    434             x = lv_area_get_width(base);
    435             y = lv_area_get_height(base) / 2 - lv_area_get_height(to_align) / 2;
    436             break;
    437 
    438         case LV_ALIGN_OUT_RIGHT_BOTTOM:
    439             x = lv_area_get_width(base);
    440             y = lv_area_get_height(base) - lv_area_get_height(to_align);
    441             break;
    442         default:
    443             x = 0;
    444             y = 0;
    445             break;
    446     }
    447 
    448     x += base->x1;
    449     y += base->y1;
    450 
    451     lv_coord_t w = lv_area_get_width(to_align);
    452     lv_coord_t h = lv_area_get_height(to_align);
    453     to_align->x1 = x + ofs_x;
    454     to_align->y1 = y + ofs_y;
    455     to_align->x2 = to_align->x1 + w - 1;
    456     to_align->y2 = to_align->y1 + h - 1;
    457 }
    458 
    459 /**********************
    460  *   STATIC FUNCTIONS
    461  **********************/
    462 
    463 static bool lv_point_within_circle(const lv_area_t * area, const lv_point_t * p)
    464 {
    465     lv_coord_t r = (area->x2 - area->x1) / 2;
    466 
    467     /*Circle center*/
    468     lv_coord_t cx = area->x1 + r;
    469     lv_coord_t cy = area->y1 + r;
    470 
    471     /*Simplify the code by moving everything to (0, 0)*/
    472     lv_coord_t px = p->x - cx;
    473     lv_coord_t py = p->y - cy;
    474 
    475     uint32_t r_sqrd = r * r;
    476     uint32_t dist = (px * px) + (py * py);
    477 
    478     if(dist <= r_sqrd)
    479         return true;
    480     else
    481         return false;
    482 }