1 /**
2  * @file lv_draw_vg_lite_arc.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../misc/lv_area_private.h"
11 #include "../lv_image_decoder_private.h"
12 #include "../lv_draw_private.h"
13 #include "lv_draw_vg_lite.h"
14 
15 #if LV_USE_DRAW_VG_LITE
16 
17 #include "lv_draw_vg_lite_type.h"
18 #include "lv_vg_lite_math.h"
19 #include "lv_vg_lite_path.h"
20 #include "lv_vg_lite_pending.h"
21 #include "lv_vg_lite_utils.h"
22 #include <math.h>
23 
24 /*********************
25  *      DEFINES
26  *********************/
27 
28 #define PI 3.1415926535897932384626433832795f
29 #define TWO_PI 6.283185307179586476925286766559f
30 #define DEG_TO_RAD 0.017453292519943295769236907684886f
31 #define RAD_TO_DEG 57.295779513082320876798154814105f
32 #define radians(deg) ((deg) * DEG_TO_RAD)
33 #define degrees(rad) ((rad) * RAD_TO_DEG)
34 
35 /**********************
36  *      TYPEDEFS
37  **********************/
38 
39 /**********************
40  *  STATIC PROTOTYPES
41  **********************/
42 
43 /**********************
44  *  STATIC VARIABLES
45  **********************/
46 
47 /**********************
48  *      MACROS
49  **********************/
50 
51 /**********************
52  *   GLOBAL FUNCTIONS
53  **********************/
54 
lv_draw_vg_lite_arc(lv_draw_unit_t * draw_unit,const lv_draw_arc_dsc_t * dsc,const lv_area_t * coords)55 void lv_draw_vg_lite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc,
56                          const lv_area_t * coords)
57 {
58     lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
59 
60     lv_area_t clip_area;
61     if(!lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) {
62         /*Fully clipped, nothing to do*/
63         return;
64     }
65 
66     float start_angle = dsc->start_angle;
67     float end_angle = dsc->end_angle;
68     float sweep_angle = end_angle - start_angle;
69 
70     while(sweep_angle < 0) {
71         sweep_angle += 360;
72     }
73 
74     while(sweep_angle > 360) {
75         sweep_angle -= 360;
76     }
77 
78     /*If the angles are the same then there is nothing to draw*/
79     if(math_zero(sweep_angle)) {
80         return;
81     }
82 
83     LV_PROFILER_DRAW_BEGIN;
84 
85     lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_FP32);
86     lv_vg_lite_path_set_bounding_box_area(path, &clip_area);
87 
88     float radius_out = dsc->radius;
89     float radius_in = dsc->radius - dsc->width;
90     float cx = dsc->center.x;
91     float cy = dsc->center.y;
92 
93     vg_lite_fill_t fill = VG_LITE_FILL_NON_ZERO;
94 
95     if(math_equal(sweep_angle, 360)) {
96         lv_vg_lite_path_append_circle(path, cx, cy, radius_out, radius_out);
97 
98         /* radius_in <= 0, normal fill circle */
99         if(radius_in > 0) {
100             lv_vg_lite_path_append_circle(path, cx, cy, radius_in, radius_in);
101         }
102         fill = VG_LITE_FILL_EVEN_ODD;
103     }
104     else {
105         float start_angle_rad = MATH_RADIANS(start_angle);
106         float end_angle_rad = MATH_RADIANS(end_angle);
107 
108         if(radius_in > 0) {
109             /* radius_out start point */
110             float start_x = radius_out * MATH_COSF(start_angle_rad) + cx;
111             float start_y = radius_out * MATH_SINF(start_angle_rad) + cy;
112 
113             /* radius_in start point */
114             float end_x = radius_in * MATH_COSF(end_angle_rad) + cx;
115             float end_y = radius_in * MATH_SINF(end_angle_rad) + cy;
116 
117             lv_vg_lite_path_move_to(path, start_x, start_y);
118 
119             /* radius_out arc */
120             lv_vg_lite_path_append_arc(path,
121                                        cx, cy,
122                                        radius_out,
123                                        start_angle,
124                                        sweep_angle,
125                                        false);
126 
127             /* line to radius_in */
128             lv_vg_lite_path_line_to(path, end_x, end_y);
129 
130             /* radius_in arc */
131             lv_vg_lite_path_append_arc(path,
132                                        cx, cy,
133                                        radius_in,
134                                        end_angle,
135                                        -sweep_angle,
136                                        false);
137 
138             /* close arc */
139             lv_vg_lite_path_close(path);
140         }
141         else {
142             /* draw a normal arc pie shape */
143             lv_vg_lite_path_append_arc(path, cx, cy, radius_out, start_angle, sweep_angle, true);
144         }
145 
146         /* draw round */
147         if(dsc->rounded && dsc->width > 0) {
148             float round_radius = radius_out > dsc->width ? dsc->width / 2.0f : radius_out / 2.0f;
149             float round_center = radius_out - round_radius;
150             float rcx1 = cx + round_center * MATH_COSF(end_angle_rad);
151             float rcy1 = cy + round_center * MATH_SINF(end_angle_rad);
152             lv_vg_lite_path_append_circle(path, rcx1, rcy1, round_radius, round_radius);
153 
154             float rcx2 = cx + round_center * MATH_COSF(start_angle_rad);
155             float rcy2 = cy + round_center * MATH_SINF(start_angle_rad);
156             lv_vg_lite_path_append_circle(path, rcx2, rcy2, round_radius, round_radius);
157         }
158     }
159 
160     lv_vg_lite_path_end(path);
161     vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
162 
163     vg_lite_matrix_t matrix = u->global_matrix;
164 
165     LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
166     LV_VG_LITE_ASSERT_PATH(vg_lite_path);
167     LV_VG_LITE_ASSERT_MATRIX(&matrix);
168 
169     if(dsc->img_src) {
170         vg_lite_buffer_t src_buf;
171         lv_image_decoder_dsc_t decoder_dsc;
172         if(lv_vg_lite_buffer_open_image(&src_buf, &decoder_dsc, dsc->img_src, false, true)) {
173 
174             vg_lite_color_t img_color = 0;
175             if(dsc->opa < LV_OPA_COVER) {
176                 /* normal image opa */
177                 src_buf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
178                 lv_memset(&img_color, dsc->opa, sizeof(img_color));
179             }
180 
181             vg_lite_matrix_t path_matrix = u->global_matrix;
182 
183             /* move image to center */
184             float img_half_w = decoder_dsc.decoded->header.w / 2.0f;
185             float img_half_h = decoder_dsc.decoded->header.h / 2.0f;
186             vg_lite_translate(cx - img_half_w, cy - img_half_h, &matrix);
187 
188             LV_VG_LITE_ASSERT_MATRIX(&matrix);
189             LV_VG_LITE_ASSERT_MATRIX(&path_matrix);
190             LV_VG_LITE_ASSERT_SRC_BUFFER(&src_buf);
191 
192             LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw_pattern");
193             LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
194                                        &u->target_buffer,
195                                        vg_lite_path,
196                                        fill,
197                                        &path_matrix,
198                                        &src_buf,
199                                        &matrix,
200                                        VG_LITE_BLEND_SRC_OVER,
201                                        VG_LITE_PATTERN_COLOR,
202                                        0,
203                                        img_color,
204                                        VG_LITE_FILTER_BI_LINEAR));
205             LV_PROFILER_DRAW_END_TAG("vg_lite_draw_pattern");
206             lv_vg_lite_pending_add(u->image_dsc_pending, &decoder_dsc);
207         }
208     }
209     else {
210         /* normal color fill */
211         LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw");
212         LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
213                                    &u->target_buffer,
214                                    vg_lite_path,
215                                    fill,
216                                    &matrix,
217                                    VG_LITE_BLEND_SRC_OVER,
218                                    lv_vg_lite_color(dsc->color, dsc->opa, true)));
219         LV_PROFILER_DRAW_END_TAG("vg_lite_draw");
220     }
221 
222     lv_vg_lite_path_drop(u, path);
223     LV_PROFILER_DRAW_END;
224 }
225 
226 /**********************
227  *   STATIC FUNCTIONS
228  **********************/
229 
230 #endif /*LV_USE_DRAW_VG_LITE*/
231