1 /**
2  * @file lv_draw_triangle.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_triangle.h"
10 #include "../lv_misc/lv_math.h"
11 #include "../lv_misc/lv_mem.h"
12 
13 /*********************
14  *      DEFINES
15  *********************/
16 
17 /**********************
18  *      TYPEDEFS
19  **********************/
20 
21 /**********************
22  *  STATIC PROTOTYPES
23  **********************/
24 
25 /**********************
26  *  STATIC VARIABLES
27  **********************/
28 
29 /**********************
30  *      MACROS
31  **********************/
32 
33 /**********************
34  *   GLOBAL FUNCTIONS
35  **********************/
36 
37 /**
38  * Draw a triangle
39  * @param points pointer to an array with 3 points
40  * @param clip_area the triangle will be drawn only in this area
41  * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
42  */
lv_draw_triangle(const lv_point_t points[],const lv_area_t * clip_area,const lv_draw_rect_dsc_t * draw_dsc)43 void lv_draw_triangle(const lv_point_t points[], const lv_area_t * clip_area, const lv_draw_rect_dsc_t * draw_dsc)
44 {
45     lv_draw_polygon(points, 3, clip_area, draw_dsc);
46 }
47 
48 /**
49  * Draw a polygon. Only convex polygons are supported
50  * @param points an array of points
51  * @param point_cnt number of points
52  * @param clip_area polygon will be drawn only in this area
53  * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
54  */
lv_draw_polygon(const lv_point_t points[],uint16_t point_cnt,const lv_area_t * clip_area,const lv_draw_rect_dsc_t * draw_dsc)55 void lv_draw_polygon(const lv_point_t points[], uint16_t point_cnt, const lv_area_t * clip_area,
56                      const lv_draw_rect_dsc_t * draw_dsc)
57 {
58     if(point_cnt < 3) return;
59     if(points == NULL) return;
60 
61     int16_t i;
62     lv_area_t poly_coords = {.x1 = LV_COORD_MAX, .y1 = LV_COORD_MAX, .x2 = LV_COORD_MIN, .y2 = LV_COORD_MIN};
63 
64     for(i = 0; i < point_cnt; i++) {
65         poly_coords.x1 = LV_MATH_MIN(poly_coords.x1, points[i].x);
66         poly_coords.y1 = LV_MATH_MIN(poly_coords.y1, points[i].y);
67         poly_coords.x2 = LV_MATH_MAX(poly_coords.x2, points[i].x);
68         poly_coords.y2 = LV_MATH_MAX(poly_coords.y2, points[i].y);
69     }
70 
71 
72     bool is_common;
73     lv_area_t poly_mask;
74     is_common = _lv_area_intersect(&poly_mask, &poly_coords, clip_area);
75     if(!is_common) return;
76 
77     /*Find the lowest point*/
78     lv_coord_t y_min = points[0].y;
79     int16_t y_min_i = 0;
80 
81     for(i = 1; i < point_cnt; i++) {
82         if(points[i].y < y_min) {
83             y_min = points[i].y;
84             y_min_i = i;
85         }
86     }
87 
88     lv_draw_mask_line_param_t * mp = _lv_mem_buf_get(sizeof(lv_draw_mask_line_param_t) * point_cnt);
89     lv_draw_mask_line_param_t * mp_next = mp;
90 
91     int32_t i_prev_left = y_min_i;
92     int32_t i_prev_right = y_min_i;
93     int32_t i_next_left;
94     int32_t i_next_right;
95     uint32_t mask_cnt = 0;
96 
97     /* Check if the order of points is inverted or not.
98      * The normal case is when the left point is on `y_min_i - 1`*/
99     i_next_left = y_min_i - 1;
100     if(i_next_left < 0) i_next_left = point_cnt + i_next_left;
101 
102     i_next_right = y_min_i + 1;
103     if(i_next_right > point_cnt - 1) i_next_right = 0;
104 
105     bool inv = false;
106     if(points[i_next_left].x > points[i_next_right].x && points[i_next_left].y < points[i_next_right].y) inv = true;
107 
108     do {
109         if(!inv) {
110             i_next_left = i_prev_left - 1;
111             if(i_next_left < 0) i_next_left = point_cnt + i_next_left;
112 
113             i_next_right = i_prev_right + 1;
114             if(i_next_right > point_cnt - 1) i_next_right = 0;
115         }
116         else {
117             i_next_left = i_prev_left + 1;
118             if(i_next_left > point_cnt - 1) i_next_left = 0;
119 
120             i_next_right = i_prev_right - 1;
121             if(i_next_right < 0) i_next_right = point_cnt + i_next_right;
122         }
123 
124         if(points[i_next_left].y >=  points[i_prev_left].y) {
125             if(points[i_next_left].y != points[i_prev_left].y &&
126                points[i_next_left].x !=  points[i_prev_left].x) {
127                 lv_draw_mask_line_points_init(mp_next, points[i_prev_left].x, points[i_prev_left].y,
128                                               points[i_next_left].x, points[i_next_left].y,
129                                               LV_DRAW_MASK_LINE_SIDE_RIGHT);
130                 lv_draw_mask_add(mp_next, mp);
131                 mp_next++;
132             }
133             mask_cnt++;
134             i_prev_left = i_next_left;
135         }
136 
137         if(mask_cnt == point_cnt) break;
138 
139         if(points[i_next_right].y >=  points[i_prev_right].y) {
140             if(points[i_next_right].y != points[i_prev_right].y &&
141                points[i_next_right].x !=  points[i_prev_right].x) {
142 
143                 lv_draw_mask_line_points_init(mp_next, points[i_prev_right].x, points[i_prev_right].y,
144                                               points[i_next_right].x, points[i_next_right].y,
145                                               LV_DRAW_MASK_LINE_SIDE_LEFT);
146                 lv_draw_mask_add(mp_next, mp);
147                 mp_next++;
148             }
149             mask_cnt++;
150             i_prev_right = i_next_right;
151         }
152 
153     } while(mask_cnt < point_cnt);
154 
155     lv_draw_rect(&poly_coords, clip_area, draw_dsc);
156 
157     lv_draw_mask_remove_custom(mp);
158 
159     _lv_mem_buf_release(mp);
160 
161 }
162 
163 /**********************
164  *   STATIC FUNCTIONS
165  **********************/
166