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