1 /**
2 * @file lv_draw_line.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include <stdio.h>
10 #include <stdbool.h>
11 #include "lv_draw.h"
12 #include "../lv_core/lv_refr.h"
13 #include "../lv_misc/lv_math.h"
14
15 /*********************
16 * DEFINES
17 *********************/
18
19 /**********************
20 * TYPEDEFS
21 **********************/
22
23 typedef struct
24 {
25 lv_point_t p1;
26 lv_point_t p2;
27 lv_point_t p_act;
28 lv_coord_t dx;
29 lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/
30 lv_coord_t dy;
31 lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/
32 lv_coord_t err;
33 lv_coord_t e2;
34 bool hor; /*Rather horizontal or vertical*/
35 } line_draw_t;
36
37 typedef struct
38 {
39 lv_coord_t width;
40 lv_coord_t width_1;
41 lv_coord_t width_half;
42 } line_width_t;
43
44 /**********************
45 * STATIC PROTOTYPES
46 **********************/
47 static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style,
48 lv_opa_t opa_scale);
49 static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style,
50 lv_opa_t opa_scale);
51 static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style,
52 lv_opa_t opa_scale);
53 static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2);
54 static bool line_next(line_draw_t * line);
55 static bool line_next_y(line_draw_t * line);
56 static bool line_next_x(line_draw_t * line);
57
58 /**********************
59 * STATIC VARIABLES
60 **********************/
61
62 /**********************
63 * MACROS
64 **********************/
65
66 /**********************
67 * GLOBAL FUNCTIONS
68 **********************/
69
70 /**
71 * Draw a line
72 * @param point1 first point of the line
73 * @param point2 second point of the line
74 * @param mask the line will be drawn only on this area
75 * @param style pointer to a line's style
76 * @param opa_scale scale down all opacities by the factor
77 */
lv_draw_line(const lv_point_t * point1,const lv_point_t * point2,const lv_area_t * mask,const lv_style_t * style,lv_opa_t opa_scale)78 void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
79 const lv_style_t * style, lv_opa_t opa_scale)
80 {
81
82 if(style->line.width == 0) return;
83 if(point1->x == point2->x && point1->y == point2->y) return;
84
85 /*Return if the points are out of the mask*/
86 if(point1->x < mask->x1 - style->line.width && point2->x < mask->x1 - style->line.width) return;
87 if(point1->x > mask->x2 + style->line.width && point2->x > mask->x2 + style->line.width) return;
88 if(point1->y < mask->y1 - style->line.width && point2->y < mask->y1 - style->line.width) return;
89 if(point1->y > mask->y2 + style->line.width && point2->y > mask->y2 + style->line.width) return;
90
91 line_draw_t main_line;
92 lv_point_t p1;
93 lv_point_t p2;
94
95 /*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/
96
97 if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) {
98
99 /*Steps less in y then x -> rather horizontal*/
100 if(point1->x < point2->x) {
101 p1.x = point1->x;
102 p1.y = point1->y;
103 p2.x = point2->x;
104 p2.y = point2->y;
105 } else {
106 p1.x = point2->x;
107 p1.y = point2->y;
108 p2.x = point1->x;
109 p2.y = point1->y;
110 }
111 } else {
112 /*Steps less in x then y -> rather vertical*/
113 if(point1->y < point2->y) {
114 p1.x = point1->x;
115 p1.y = point1->y;
116 p2.x = point2->x;
117 p2.y = point2->y;
118 } else {
119 p1.x = point2->x;
120 p1.y = point2->y;
121 p2.x = point1->x;
122 p2.y = point1->y;
123 }
124 }
125
126 line_init(&main_line, &p1, &p2);
127
128 /*Special case draw a horizontal line*/
129 if(main_line.p1.y == main_line.p2.y) {
130 line_draw_hor(&main_line, mask, style, opa_scale);
131 }
132 /*Special case draw a vertical line*/
133 else if(main_line.p1.x == main_line.p2.x) {
134 line_draw_ver(&main_line, mask, style, opa_scale);
135 }
136 /*Arbitrary skew line*/
137 else {
138 bool dir_ori = false;
139 #if LV_ANTIALIAS
140 bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
141 if(aa) {
142 lv_point_t p_tmp;
143
144 if(main_line.hor) {
145 if(main_line.p1.y < main_line.p2.y) {
146 dir_ori = true;
147 p_tmp.x = main_line.p2.x;
148 p_tmp.y = main_line.p2.y - 1;
149 line_init(&main_line, &p1, &p_tmp);
150 main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
151 } else if(main_line.p1.y > main_line.p2.y) {
152 dir_ori = false;
153 p_tmp.x = main_line.p2.x;
154 p_tmp.y = main_line.p2.y + 1;
155 line_init(&main_line, &p1, &p_tmp);
156 main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
157 }
158 } else {
159 if(main_line.p1.x < main_line.p2.x) {
160 dir_ori = true;
161 p_tmp.x = main_line.p2.x - 1;
162 p_tmp.y = main_line.p2.y;
163 line_init(&main_line, &p1, &p_tmp);
164 main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
165 } else if(main_line.p1.x > main_line.p2.x) {
166 dir_ori = false;
167 p_tmp.x = main_line.p2.x + 1;
168 p_tmp.y = main_line.p2.y;
169 line_init(&main_line, &p1, &p_tmp);
170 main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
171 }
172 }
173 }
174 #endif
175 line_draw_skew(&main_line, dir_ori, mask, style, opa_scale);
176 }
177 }
178
179 /**********************
180 * STATIC FUNCTIONS
181 **********************/
182
line_draw_hor(line_draw_t * main_line,const lv_area_t * mask,const lv_style_t * style,lv_opa_t opa_scale)183 static void line_draw_hor(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
184 {
185 lv_coord_t width = style->line.width - 1;
186 lv_coord_t width_half = width >> 1;
187 lv_coord_t width_1 = width & 0x1;
188 lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
189
190 lv_area_t act_area;
191 act_area.x1 = main_line->p1.x;
192 act_area.x2 = main_line->p2.x;
193 act_area.y1 = main_line->p1.y - width_half - width_1;
194 act_area.y2 = main_line->p2.y + width_half;
195
196 lv_area_t draw_area;
197 draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
198 draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
199 draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
200 draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
201 lv_draw_fill(&draw_area, mask, style->line.color, opa);
202 }
203
line_draw_ver(line_draw_t * main_line,const lv_area_t * mask,const lv_style_t * style,lv_opa_t opa_scale)204 static void line_draw_ver(line_draw_t * main_line, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale)
205 {
206 lv_coord_t width = style->line.width - 1;
207 lv_coord_t width_half = width >> 1;
208 lv_coord_t width_1 = width & 0x1;
209 lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
210
211 lv_area_t act_area;
212 act_area.x1 = main_line->p1.x - width_half;
213 act_area.x2 = main_line->p2.x + width_half + width_1;
214 act_area.y1 = main_line->p1.y;
215 act_area.y2 = main_line->p2.y;
216
217 lv_area_t draw_area;
218 draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
219 draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
220 draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
221 draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
222 lv_draw_fill(&draw_area, mask, style->line.color, opa);
223 }
224
line_draw_skew(line_draw_t * main_line,bool dir_ori,const lv_area_t * mask,const lv_style_t * style,lv_opa_t opa_scale)225 static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_t * mask, const lv_style_t * style,
226 lv_opa_t opa_scale)
227 {
228
229 lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
230 #if LV_ANTIALIAS
231 bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
232 #endif
233 lv_point_t vect_main, vect_norm;
234 vect_main.x = main_line->p2.x - main_line->p1.x;
235 vect_main.y = main_line->p2.y - main_line->p1.y;
236
237 if(main_line->hor) {
238 if(main_line->p1.y < main_line->p2.y + dir_ori) {
239 vect_norm.x = -vect_main.y;
240 vect_norm.y = vect_main.x;
241 } else {
242 vect_norm.x = vect_main.y;
243 vect_norm.y = -vect_main.x;
244 }
245 } else {
246 if(main_line->p1.x < main_line->p2.x + dir_ori) {
247 vect_norm.x = vect_main.y;
248 vect_norm.y = -vect_main.x;
249 } else {
250 vect_norm.x = -vect_main.y;
251 vect_norm.y = vect_main.x;
252 }
253 }
254
255 /* In case of a short but tick line the perpendicular ending is longer then the real line.
256 * it would break the calculations so make the normal vector larger*/
257 vect_norm.x = vect_norm.x << 4;
258 vect_norm.y = vect_norm.y << 4;
259
260 lv_coord_t width;
261 width = style->line.width;
262
263 /* The pattern stores the points of the line ending. It has the good direction and length.
264 * The worth case is the 45° line where pattern can have 1.41 x `width` points*/
265
266 lv_coord_t pattern_size = width * 2;
267 lv_point_t * pattern = lv_draw_get_buf(pattern_size * sizeof(lv_point_t));
268 lv_coord_t i = 0;
269
270 /*Create a perpendicular pattern (a small line)*/
271 if(width != 0) {
272 line_draw_t pattern_line;
273 lv_point_t p0 = {0, 0};
274 line_init(&pattern_line, &p0, &vect_norm);
275
276 uint32_t width_sqr = width * width;
277 /* Run for a lot of times. Meanwhile the real width will be determined as well */
278 for(i = 0; i < (lv_coord_t)pattern_size - 1; i++) {
279 pattern[i].x = pattern_line.p_act.x;
280 pattern[i].y = pattern_line.p_act.y;
281
282 /*Finish the pattern line if it's length equal to the desired width (Use Pythagoras
283 * theorem)*/
284 uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y;
285 if(sqr >= width_sqr) {
286 width = i;
287 #if LV_ANTIALIAS
288 if(aa) width--;
289 #endif
290 break;
291 }
292
293 line_next(&pattern_line);
294 }
295 }
296
297 #if LV_ANTIALIAS
298 lv_coord_t aa_last_corner;
299 lv_coord_t width_safe = width;
300 if(aa) {
301 if(width == 0) width_safe = 1;
302
303 aa_last_corner = 0;
304 }
305 #endif
306
307 lv_coord_t x_center_ofs = 0;
308 lv_coord_t y_center_ofs = 0;
309
310 if(width != 0) {
311 x_center_ofs = pattern[width - 1].x / 2;
312 y_center_ofs = pattern[width - 1].y / 2;
313 } else {
314 if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y--;
315 if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x--;
316 }
317
318 /* Make the coordinates relative to the center */
319 for(i = 0; i < width; i++) {
320 pattern[i].x -= x_center_ofs;
321 pattern[i].y -= y_center_ofs;
322 #if LV_ANTIALIAS
323 if(aa) {
324 if(i != 0) {
325 if(main_line->hor) {
326 if(pattern[i - 1].x != pattern[i].x) {
327 lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y;
328 if(main_line->sy < 0) {
329 lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
330 main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1, seg_w, mask,
331 style->line.color, opa);
332
333 lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
334 main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1, -seg_w, mask,
335 style->line.color, opa);
336 } else {
337 lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
338 main_line->p1.y + pattern[aa_last_corner].y, seg_w, mask,
339 style->line.color, opa);
340
341 lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
342 main_line->p2.y + pattern[aa_last_corner].y, -seg_w, mask,
343 style->line.color, opa);
344 }
345 aa_last_corner = i;
346 }
347 } else {
348 if(pattern[i - 1].y != pattern[i].y) {
349 lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x;
350 if(main_line->sx < 0) {
351 lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1,
352 main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask,
353 style->line.color, opa);
354
355 lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1,
356 main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask,
357 style->line.color, opa);
358 } else {
359 lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x,
360 main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask,
361 style->line.color, opa);
362
363 lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x,
364 main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask,
365 style->line.color, opa);
366 }
367 aa_last_corner = i;
368 }
369 }
370 }
371 }
372 #endif
373 }
374
375 #if LV_ANTIALIAS
376 /*Add the last part of anti-aliasing for the perpendicular ending*/
377 if(width != 0 && aa) { /*Due to rounding error with very thin lines it looks ugly*/
378 if(main_line->hor) {
379 lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y;
380 if(main_line->sy < 0) {
381 lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
382 main_line->p1.y + pattern[aa_last_corner].y + seg_w, seg_w + main_line->sy, mask,
383 style->line.color, opa);
384
385 lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
386 main_line->p2.y + pattern[aa_last_corner].y + seg_w, -(seg_w + main_line->sy), mask,
387 style->line.color, opa);
388
389 } else {
390 lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
391 main_line->p1.y + pattern[aa_last_corner].y, seg_w + main_line->sy, mask,
392 style->line.color, opa);
393
394 lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
395 main_line->p2.y + pattern[aa_last_corner].y, -(seg_w + main_line->sy), mask,
396 style->line.color, opa);
397 }
398 } else {
399 lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x;
400 if(main_line->sx < 0) {
401 lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w,
402 main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask,
403 style->line.color, opa);
404
405 lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w,
406 main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask,
407 style->line.color, opa);
408
409 } else {
410 lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x,
411 main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask,
412 style->line.color, opa);
413
414 lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x,
415 main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask,
416 style->line.color, opa);
417 }
418 }
419 }
420 #endif
421
422 #if LV_ANTIALIAS
423
424 /*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/
425 lv_coord_t aa_shift1 = 0;
426 lv_coord_t aa_shift2 = 0;
427 if(aa) {
428 if(main_line->hor == false) {
429 if(main_line->sx < 0) {
430 aa_shift1 = -1;
431 aa_shift2 = width == 0 ? 0 : aa_shift1;
432 } else {
433 aa_shift2 = 1;
434 aa_shift1 = width == 0 ? 0 : aa_shift2;
435 }
436 } else {
437 if(main_line->sy < 0) {
438 aa_shift1 = -1;
439 aa_shift2 = width == 0 ? 0 : aa_shift1;
440 } else {
441 aa_shift2 = 1;
442 aa_shift1 = width == 0 ? 0 : aa_shift2;
443 }
444 }
445 }
446 #endif
447
448 volatile lv_point_t prev_p;
449 prev_p.x = main_line->p1.x;
450 prev_p.y = main_line->p1.y;
451 lv_area_t draw_area;
452 bool first_run = true;
453
454 if(main_line->hor) {
455 while(line_next_y(main_line)) {
456 for(i = 0; i < width; i++) {
457 draw_area.x1 = prev_p.x + pattern[i].x;
458 draw_area.y1 = prev_p.y + pattern[i].y;
459 draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1;
460 draw_area.y2 = draw_area.y1;
461 lv_draw_fill(&draw_area, mask, style->line.color, opa);
462
463 /* Fill the gaps
464 * When stepping in y one pixel remains empty on every corner (don't do this on the
465 * first segment ) */
466 if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
467 lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
468 }
469 }
470
471 #if LV_ANTIALIAS
472 if(aa) {
473 lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
474 -(main_line->p_act.x - prev_p.x), mask, style->line.color, opa);
475 lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x,
476 prev_p.y + pattern[width_safe - 1].y + aa_shift2, main_line->p_act.x - prev_p.x,
477 mask, style->line.color, opa);
478 }
479 #endif
480
481 first_run = false;
482
483 prev_p.x = main_line->p_act.x;
484 prev_p.y = main_line->p_act.y;
485 }
486
487 for(i = 0; i < width; i++) {
488 draw_area.x1 = prev_p.x + pattern[i].x;
489 draw_area.y1 = prev_p.y + pattern[i].y;
490 draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x;
491 draw_area.y2 = draw_area.y1;
492 lv_draw_fill(&draw_area, mask, style->line.color, opa);
493
494 /* Fill the gaps
495 * When stepping in y one pixel remains empty on every corner */
496 if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
497 lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
498 }
499 }
500
501 #if LV_ANTIALIAS
502 if(aa) {
503 lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
504 -(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa);
505 lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
506 main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa);
507 }
508 #endif
509 }
510 /*Rather a vertical line*/
511 else {
512
513 while(line_next_x(main_line)) {
514 for(i = 0; i < width; i++) {
515 draw_area.x1 = prev_p.x + pattern[i].x;
516 draw_area.y1 = prev_p.y + pattern[i].y;
517 draw_area.x2 = draw_area.x1;
518 draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1;
519
520 lv_draw_fill(&draw_area, mask, style->line.color, opa);
521
522 /* Fill the gaps
523 * When stepping in x one pixel remains empty on every corner (don't do this on the
524 * first segment ) */
525 if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
526 lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
527 }
528 }
529
530 #if LV_ANTIALIAS
531 if(aa) {
532 lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
533 -(main_line->p_act.y - prev_p.y), mask, style->line.color, opa);
534 lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2,
535 prev_p.y + pattern[width_safe - 1].y, main_line->p_act.y - prev_p.y, mask,
536 style->line.color, opa);
537 }
538 #endif
539
540 first_run = false;
541
542 prev_p.x = main_line->p_act.x;
543 prev_p.y = main_line->p_act.y;
544 }
545
546 /*Draw the last part*/
547 for(i = 0; i < width; i++) {
548 draw_area.x1 = prev_p.x + pattern[i].x;
549 draw_area.y1 = prev_p.y + pattern[i].y;
550 draw_area.x2 = draw_area.x1;
551 draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y;
552
553 lv_draw_fill(&draw_area, mask, style->line.color, opa);
554
555 /* Fill the gaps
556 * When stepping in x one pixel remains empty on every corner */
557 if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
558 lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
559 }
560 }
561
562 #if LV_ANTIALIAS
563 if(aa) {
564 lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
565 -(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa);
566 lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
567 main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa);
568 }
569 #endif
570 }
571 }
572
line_init(line_draw_t * line,const lv_point_t * p1,const lv_point_t * p2)573 static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2)
574 {
575 line->p1.x = p1->x;
576 line->p1.y = p1->y;
577 line->p2.x = p2->x;
578 line->p2.y = p2->y;
579
580 line->dx = LV_MATH_ABS(line->p2.x - line->p1.x);
581 line->sx = line->p1.x < line->p2.x ? 1 : -1;
582 line->dy = LV_MATH_ABS(line->p2.y - line->p1.y);
583 line->sy = line->p1.y < line->p2.y ? 1 : -1;
584 line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2;
585 line->e2 = 0;
586 line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/
587
588 line->p_act.x = line->p1.x;
589 line->p_act.y = line->p1.y;
590 }
591
line_next(line_draw_t * line)592 static bool line_next(line_draw_t * line)
593 {
594 if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false;
595 line->e2 = line->err;
596 if(line->e2 > -line->dx) {
597 line->err -= line->dy;
598 line->p_act.x += line->sx;
599 }
600 if(line->e2 < line->dy) {
601 line->err += line->dx;
602 line->p_act.y += line->sy;
603 }
604 return true;
605 }
606
607 /**
608 * Iterate until step one in y direction.
609 * @param line
610 * @return
611 */
line_next_y(line_draw_t * line)612 static bool line_next_y(line_draw_t * line)
613 {
614 lv_coord_t last_y = line->p_act.y;
615
616 do {
617 if(!line_next(line)) return false;
618 } while(last_y == line->p_act.y);
619
620 return true;
621 }
622
623 /**
624 * Iterate until step one in x direction.
625 * @param line
626 * @return
627 */
line_next_x(line_draw_t * line)628 static bool line_next_x(line_draw_t * line)
629 {
630 lv_coord_t last_x = line->p_act.x;
631
632 do {
633 if(!line_next(line)) return false;
634 } while(last_x == line->p_act.x);
635
636 return true;
637 }
638