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 }