1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00
lvgl/src/lv_draw/lv_draw_line.c

709 lines
24 KiB
C
Raw Normal View History

/**
* @file lv_draw_line.c
*
*/
/*********************
* INCLUDES
*********************/
#include <stdio.h>
#include <stdbool.h>
#include "lv_draw.h"
#include "../lv_core/lv_refr.h"
#include "../lv_misc/lv_math.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/*
* 8192
8193
8196
8201
8208
8217
8228
8241
8256
8273
8291
8312
8335
8359
8386
8414
8444
8476
8510
8545
8583
8622
8662
8705
8749
8795
8842
8891
8942
8994
9047
9102
9159
9217
9276
9337
9399
9462
9527
9593
9660
9729
9798
9869
9941
10014
10088
10164
10240
10317
10396
10475
10555
10636
10718
10801
10885
10970
11056
11142
11229
11317
11406
11495
11585
*
*
* */
2019-04-04 07:15:40 +02:00
typedef struct
{
2018-06-19 09:49:58 +02:00
lv_point_t p1;
lv_point_t p2;
lv_point_t p_act;
lv_coord_t dx;
2019-04-04 07:15:40 +02:00
lv_coord_t sx; /*-1: x1 < x2; 1: x2 >= x1*/
2018-06-19 09:49:58 +02:00
lv_coord_t dy;
2019-04-04 07:15:40 +02:00
lv_coord_t sy; /*-1: y1 < y2; 1: y2 >= y1*/
2018-06-19 09:49:58 +02:00
lv_coord_t err;
lv_coord_t e2;
2019-04-04 07:15:40 +02:00
bool hor; /*Rather horizontal or vertical*/
2018-06-19 09:49:58 +02:00
} line_draw_t;
2019-04-04 07:15:40 +02:00
typedef struct
{
2018-06-19 09:49:58 +02:00
lv_coord_t width;
lv_coord_t width_1;
lv_coord_t width_half;
} line_width_t;
/**********************
* STATIC PROTOTYPES
**********************/
2019-04-04 07:15:40 +02:00
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);
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);
2019-06-06 06:05:40 +02:00
static void 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);
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2);
static bool line_next(line_draw_t * line);
static bool line_next_y(line_draw_t * line);
static bool line_next_x(line_draw_t * line);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Draw a line
2018-06-14 13:08:19 +02:00
* @param point1 first point of the line
* @param point2 second point of the line
* @param mask the line will be drawn only on this area
* @param style pointer to a line's style
* @param opa_scale scale down all opacities by the factor
*/
void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask,
2019-04-04 07:15:40 +02:00
const lv_style_t * style, lv_opa_t opa_scale)
{
if(style->line.width == 0) return;
if(point1->x == point2->x && point1->y == point2->y) return;
/*Return if the points are out of the mask*/
2019-07-03 06:54:10 +02:00
if(point1->x < mask->x1 - style->line.width && point2->x < mask->x1 - style->line.width) return;
if(point1->x > mask->x2 + style->line.width && point2->x > mask->x2 + style->line.width) return;
if(point1->y < mask->y1 - style->line.width && point2->y < mask->y1 - style->line.width) return;
if(point1->y > mask->y2 + style->line.width && point2->y > mask->y2 + style->line.width) return;
line_draw_t main_line;
lv_point_t p1;
lv_point_t p2;
/*If the line if rather vertical then be sure y1 < y2 else x1 < x2*/
2018-06-19 09:49:58 +02:00
if(LV_MATH_ABS(point1->x - point2->x) > LV_MATH_ABS(point1->y - point2->y)) {
/*Steps less in y then x -> rather horizontal*/
if(point1->x < point2->x) {
p1.x = point1->x;
p1.y = point1->y;
p2.x = point2->x;
p2.y = point2->y;
} else {
p1.x = point2->x;
p1.y = point2->y;
p2.x = point1->x;
p2.y = point1->y;
}
} else {
2018-06-19 09:49:58 +02:00
/*Steps less in x then y -> rather vertical*/
if(point1->y < point2->y) {
p1.x = point1->x;
p1.y = point1->y;
p2.x = point2->x;
p2.y = point2->y;
} else {
p1.x = point2->x;
p1.y = point2->y;
p2.x = point1->x;
p2.y = point1->y;
}
}
line_init(&main_line, &p1, &p2);
/*Special case draw a horizontal line*/
2018-06-19 09:49:58 +02:00
if(main_line.p1.y == main_line.p2.y) {
line_draw_hor(&main_line, mask, style, opa_scale);
}
/*Special case draw a vertical line*/
2018-06-19 09:49:58 +02:00
else if(main_line.p1.x == main_line.p2.x) {
line_draw_ver(&main_line, mask, style, opa_scale);
}
/*Arbitrary skew line*/
else {
bool dir_ori = false;
#if LV_ANTIALIAS
bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
if(aa) {
lv_point_t p_tmp;
if(main_line.hor) {
if(main_line.p1.y < main_line.p2.y) {
dir_ori = true;
p_tmp.x = main_line.p2.x;
p_tmp.y = main_line.p2.y - 1;
line_init(&main_line, &p1, &p_tmp);
2019-06-06 06:05:40 +02:00
main_line.sy = LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
2019-04-04 07:15:40 +02:00
} else if(main_line.p1.y > main_line.p2.y) {
dir_ori = false;
p_tmp.x = main_line.p2.x;
p_tmp.y = main_line.p2.y + 1;
line_init(&main_line, &p1, &p_tmp);
2019-06-06 06:05:40 +02:00
main_line.sy = -LV_MATH_ABS(main_line.sy); /*The sign can change if the line becomes horizontal*/
}
2019-04-04 07:15:40 +02:00
} else {
if(main_line.p1.x < main_line.p2.x) {
dir_ori = true;
p_tmp.x = main_line.p2.x - 1;
p_tmp.y = main_line.p2.y;
line_init(&main_line, &p1, &p_tmp);
2019-06-06 06:05:40 +02:00
main_line.sx = LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
2019-04-04 07:15:40 +02:00
} else if(main_line.p1.x > main_line.p2.x) {
dir_ori = false;
p_tmp.x = main_line.p2.x + 1;
p_tmp.y = main_line.p2.y;
line_init(&main_line, &p1, &p_tmp);
2019-06-06 06:05:40 +02:00
main_line.sx = -LV_MATH_ABS(main_line.sx); /*The sign can change if the line becomes vertical*/
}
}
}
#endif
line_draw_skew(&main_line, dir_ori, mask, style, opa_scale);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
2019-06-06 06:05:40 +02:00
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)
{
2019-04-04 07:15:40 +02:00
lv_coord_t width = style->line.width - 1;
2018-06-19 09:49:58 +02:00
lv_coord_t width_half = width >> 1;
2019-04-04 07:15:40 +02:00
lv_coord_t width_1 = width & 0x1;
2019-06-06 06:05:40 +02:00
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
lv_area_t act_area;
act_area.x1 = main_line->p1.x;
act_area.x2 = main_line->p2.x;
act_area.y1 = main_line->p1.y - width_half - width_1;
2019-04-04 07:15:40 +02:00
act_area.y2 = main_line->p2.y + width_half;
lv_area_t draw_area;
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
2019-02-13 01:40:22 +01:00
lv_draw_fill(&draw_area, mask, style->line.color, opa);
}
2019-06-06 06:05:40 +02:00
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)
{
2019-04-04 07:15:40 +02:00
lv_coord_t width = style->line.width - 1;
2018-06-19 09:49:58 +02:00
lv_coord_t width_half = width >> 1;
2019-04-04 07:15:40 +02:00
lv_coord_t width_1 = width & 0x1;
2019-06-06 06:05:40 +02:00
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
2018-06-14 13:08:19 +02:00
lv_area_t act_area;
act_area.x1 = main_line->p1.x - width_half;
act_area.x2 = main_line->p2.x + width_half + width_1;
act_area.y1 = main_line->p1.y;
act_area.y2 = main_line->p2.y;
lv_area_t draw_area;
draw_area.x1 = LV_MATH_MIN(act_area.x1, act_area.x2);
draw_area.x2 = LV_MATH_MAX(act_area.x1, act_area.x2);
draw_area.y1 = LV_MATH_MIN(act_area.y1, act_area.y2);
draw_area.y2 = LV_MATH_MAX(act_area.y1, act_area.y2);
2019-02-13 01:40:22 +01:00
lv_draw_fill(&draw_area, mask, style->line.color, opa);
}
2019-06-06 06:05:40 +02:00
static void 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)
{
2018-09-23 21:54:55 +02:00
2019-06-06 06:05:40 +02:00
lv_opa_t opa = opa_scale == LV_OPA_COVER ? style->line.opa : (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
#if LV_ANTIALIAS
bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
#endif
2018-06-19 09:49:58 +02:00
lv_point_t vect_main, vect_norm;
vect_main.x = main_line->p2.x - main_line->p1.x;
vect_main.y = main_line->p2.y - main_line->p1.y;
if(main_line->hor) {
if(main_line->p1.y < main_line->p2.y + dir_ori) {
2019-04-04 07:15:40 +02:00
vect_norm.x = -vect_main.y;
2018-06-19 09:49:58 +02:00
vect_norm.y = vect_main.x;
} else {
vect_norm.x = vect_main.y;
vect_norm.y = -vect_main.x;
}
} else {
if(main_line->p1.x < main_line->p2.x + dir_ori) {
2018-06-19 09:49:58 +02:00
vect_norm.x = vect_main.y;
2019-04-04 07:15:40 +02:00
vect_norm.y = -vect_main.x;
2018-06-19 09:49:58 +02:00
} else {
2019-04-04 07:15:40 +02:00
vect_norm.x = -vect_main.y;
2018-06-19 09:49:58 +02:00
vect_norm.y = vect_main.x;
}
}
/* In case of a short but tick line the perpendicular ending is longer then the real line.
* it would break the calculations so make the normal vector larger*/
vect_norm.x = vect_norm.x << 4;
vect_norm.y = vect_norm.y << 4;
2018-09-23 21:54:55 +02:00
lv_coord_t width;
width = style->line.width;
/* The pattern stores the points of the line ending. It has the good direction and length.
* The worth case is the 45° line where pattern can have 1.41 x `width` points*/
2019-08-01 21:01:02 +02:00
lv_coord_t pattern_size = width * 2;
lv_point_t * pattern = lv_draw_get_buf(pattern_size * sizeof(lv_point_t));
2018-09-25 11:23:50 +02:00
lv_coord_t i = 0;
2018-06-19 09:49:58 +02:00
/*Create a perpendicular pattern (a small line)*/
if(width != 0) {
line_draw_t pattern_line;
lv_point_t p0 = {0, 0};
line_init(&pattern_line, &p0, &vect_norm);
uint32_t width_sqr = width * width;
2018-09-23 21:54:55 +02:00
/* Run for a lot of times. Meanwhile the real width will be determined as well */
2019-08-01 21:01:02 +02:00
for(i = 0; i < (lv_coord_t)pattern_size - 1; i++) {
2018-06-19 09:49:58 +02:00
pattern[i].x = pattern_line.p_act.x;
pattern[i].y = pattern_line.p_act.y;
2019-04-04 07:15:40 +02:00
/*Finish the pattern line if it's length equal to the desired width (Use Pythagoras
* theorem)*/
2019-06-06 06:05:40 +02:00
uint32_t sqr = pattern_line.p_act.x * pattern_line.p_act.x + pattern_line.p_act.y * pattern_line.p_act.y;
if(sqr >= width_sqr) {
width = i;
#if LV_ANTIALIAS
if(aa) width--;
#endif
break;
}
2018-06-19 09:49:58 +02:00
line_next(&pattern_line);
}
}
#if LV_ANTIALIAS
lv_coord_t aa_last_corner;
2018-10-05 15:15:19 +02:00
lv_coord_t width_safe = width;
if(aa) {
if(width == 0) width_safe = 1;
2018-10-05 15:15:19 +02:00
aa_last_corner = 0;
}
#endif
2018-12-11 18:00:32 +01:00
lv_coord_t x_center_ofs = 0;
lv_coord_t y_center_ofs = 0;
2018-12-11 18:00:32 +01:00
if(width != 0) {
x_center_ofs = pattern[width - 1].x / 2;
y_center_ofs = pattern[width - 1].y / 2;
2019-04-04 07:15:40 +02:00
} else {
if(main_line->hor && main_line->p1.y >= main_line->p2.y + dir_ori) pattern[0].y--;
if(!main_line->hor && main_line->p1.x >= main_line->p2.x + dir_ori) pattern[0].x--;
2018-12-11 18:00:32 +01:00
}
2018-06-19 09:49:58 +02:00
/* Make the coordinates relative to the center */
for(i = 0; i < width; i++) {
2018-12-11 18:00:32 +01:00
pattern[i].x -= x_center_ofs;
pattern[i].y -= y_center_ofs;
#if LV_ANTIALIAS
if(aa) {
if(i != 0) {
if(main_line->hor) {
if(pattern[i - 1].x != pattern[i].x) {
lv_coord_t seg_w = pattern[i].y - pattern[aa_last_corner].y;
if(main_line->sy < 0) {
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y + seg_w + 1, seg_w, mask,
style->line.color, opa);
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y + seg_w + 1, -seg_w, mask,
style->line.color, opa);
} else {
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y, seg_w, mask,
style->line.color, opa);
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y, -seg_w, mask,
style->line.color, opa);
}
aa_last_corner = i;
2018-06-19 09:49:58 +02:00
}
} else {
if(pattern[i - 1].y != pattern[i].y) {
lv_coord_t seg_w = pattern[i].x - pattern[aa_last_corner].x;
if(main_line->sx < 0) {
2019-06-06 06:05:40 +02:00
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w + 1,
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask,
style->line.color, opa);
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w + 1,
main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask,
style->line.color, opa);
} else {
2019-04-04 07:15:40 +02:00
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w, mask,
style->line.color, opa);
2019-04-04 07:15:40 +02:00
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y + 1, -seg_w, mask,
style->line.color, opa);
}
aa_last_corner = i;
2018-06-19 09:49:58 +02:00
}
}
}
2018-06-19 09:49:58 +02:00
}
#endif
2018-06-19 09:49:58 +02:00
}
#if LV_ANTIALIAS
2018-06-19 09:49:58 +02:00
/*Add the last part of anti-aliasing for the perpendicular ending*/
2019-04-04 07:15:40 +02:00
if(width != 0 && aa) { /*Due to rounding error with very thin lines it looks ugly*/
if(main_line->hor) {
lv_coord_t seg_w = pattern[width_safe - 1].y - pattern[aa_last_corner].y;
if(main_line->sy < 0) {
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y + seg_w, seg_w + main_line->sy, mask,
style->line.color, opa);
2018-06-19 09:49:58 +02:00
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y + seg_w, -(seg_w + main_line->sy), mask,
style->line.color, opa);
2018-06-19 09:49:58 +02:00
} else {
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p1.x + pattern[aa_last_corner].x - 1,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y, seg_w + main_line->sy, mask,
style->line.color, opa);
2019-04-04 07:15:40 +02:00
lv_draw_aa_ver_seg(main_line->p2.x + pattern[aa_last_corner].x + 1,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y, -(seg_w + main_line->sy), mask,
style->line.color, opa);
}
2018-06-19 09:49:58 +02:00
} else {
lv_coord_t seg_w = pattern[width_safe - 1].x - pattern[aa_last_corner].x;
if(main_line->sx < 0) {
2019-04-04 07:15:40 +02:00
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x + seg_w,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask,
style->line.color, opa);
2018-06-19 09:49:58 +02:00
2019-04-04 07:15:40 +02:00
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x + seg_w,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask,
style->line.color, opa);
2018-06-19 09:49:58 +02:00
} else {
2019-04-04 07:15:40 +02:00
lv_draw_aa_hor_seg(main_line->p1.x + pattern[aa_last_corner].x,
2019-06-06 06:05:40 +02:00
main_line->p1.y + pattern[aa_last_corner].y - 1, seg_w + main_line->sx, mask,
style->line.color, opa);
2018-06-19 09:49:58 +02:00
2019-04-04 07:15:40 +02:00
lv_draw_aa_hor_seg(main_line->p2.x + pattern[aa_last_corner].x,
2019-06-06 06:05:40 +02:00
main_line->p2.y + pattern[aa_last_corner].y + 1, -(seg_w + main_line->sx), mask,
style->line.color, opa);
}
2018-06-19 09:49:58 +02:00
}
}
#endif
#if LV_ANTIALIAS
2018-06-19 09:49:58 +02:00
/*Shift the anti aliasing on the edges (-1, 1 or 0 (zero only in case width == 0))*/
2019-04-09 16:18:04 -04:00
lv_coord_t aa_shift1 = 0;
lv_coord_t aa_shift2 = 0;
if(aa) {
if(main_line->hor == false) {
if(main_line->sx < 0) {
aa_shift1 = -1;
aa_shift2 = width == 0 ? 0 : aa_shift1;
} else {
aa_shift2 = 1;
aa_shift1 = width == 0 ? 0 : aa_shift2;
}
2018-06-19 09:49:58 +02:00
} else {
if(main_line->sy < 0) {
aa_shift1 = -1;
aa_shift2 = width == 0 ? 0 : aa_shift1;
} else {
aa_shift2 = 1;
aa_shift1 = width == 0 ? 0 : aa_shift2;
}
2018-06-19 09:49:58 +02:00
}
}
#endif
2018-06-19 09:49:58 +02:00
volatile lv_point_t prev_p;
prev_p.x = main_line->p1.x;
prev_p.y = main_line->p1.y;
lv_area_t draw_area;
bool first_run = true;
if(main_line->hor) {
while(line_next_y(main_line)) {
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x - 1;
draw_area.y2 = draw_area.y1;
2019-02-13 01:40:22 +01:00
lv_draw_fill(&draw_area, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
/* Fill the gaps
2019-04-04 07:15:40 +02:00
* When stepping in y one pixel remains empty on every corner (don't do this on the
* first segment ) */
2018-06-19 09:49:58 +02:00
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
2019-06-06 06:05:40 +02:00
lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
}
}
#if LV_ANTIALIAS
if(aa) {
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
2019-04-04 07:15:40 +02:00
-(main_line->p_act.x - prev_p.x), mask, style->line.color, opa);
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x,
2019-06-06 06:05:40 +02:00
prev_p.y + pattern[width_safe - 1].y + aa_shift2, main_line->p_act.x - prev_p.x,
mask, style->line.color, opa);
}
#endif
2018-06-19 09:49:58 +02:00
first_run = false;
2018-06-19 09:49:58 +02:00
prev_p.x = main_line->p_act.x;
prev_p.y = main_line->p_act.y;
}
2018-06-19 09:49:58 +02:00
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1 + main_line->p_act.x - prev_p.x;
draw_area.y2 = draw_area.y1;
2019-02-13 01:40:22 +01:00
lv_draw_fill(&draw_area, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
/* Fill the gaps
* When stepping in y one pixel remains empty on every corner */
if(i != 0 && pattern[i].x != pattern[i - 1].x && !first_run) {
2019-06-06 06:05:40 +02:00
lv_draw_px(draw_area.x1, draw_area.y1 - main_line->sy, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
}
}
#if LV_ANTIALIAS
if(aa) {
lv_draw_aa_hor_seg(prev_p.x + pattern[0].x, prev_p.y + pattern[0].y - aa_shift1,
2019-04-04 07:15:40 +02:00
-(main_line->p_act.x - prev_p.x + 1), mask, style->line.color, opa);
2019-06-06 06:05:40 +02:00
lv_draw_aa_hor_seg(prev_p.x + pattern[width_safe - 1].x, prev_p.y + pattern[width_safe - 1].y + aa_shift2,
2019-04-04 07:15:40 +02:00
main_line->p_act.x - prev_p.x + 1, mask, style->line.color, opa);
}
#endif
2018-06-19 09:49:58 +02:00
}
/*Rather a vertical line*/
else {
2018-06-19 09:49:58 +02:00
while(line_next_x(main_line)) {
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1;
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y - 1;
2019-02-13 01:40:22 +01:00
lv_draw_fill(&draw_area, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
/* Fill the gaps
2019-04-04 07:15:40 +02:00
* When stepping in x one pixel remains empty on every corner (don't do this on the
* first segment ) */
2018-06-19 09:49:58 +02:00
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
2019-06-06 06:05:40 +02:00
lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
}
}
#if LV_ANTIALIAS
if(aa) {
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
2019-04-04 07:15:40 +02:00
-(main_line->p_act.y - prev_p.y), mask, style->line.color, opa);
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2,
2019-06-06 06:05:40 +02:00
prev_p.y + pattern[width_safe - 1].y, main_line->p_act.y - prev_p.y, mask,
style->line.color, opa);
}
#endif
2018-06-19 09:49:58 +02:00
first_run = false;
2018-06-19 09:49:58 +02:00
prev_p.x = main_line->p_act.x;
prev_p.y = main_line->p_act.y;
}
2018-06-19 09:49:58 +02:00
/*Draw the last part*/
for(i = 0; i < width; i++) {
draw_area.x1 = prev_p.x + pattern[i].x;
draw_area.y1 = prev_p.y + pattern[i].y;
draw_area.x2 = draw_area.x1;
draw_area.y2 = draw_area.y1 + main_line->p_act.y - prev_p.y;
2019-02-13 01:40:22 +01:00
lv_draw_fill(&draw_area, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
/* Fill the gaps
* When stepping in x one pixel remains empty on every corner */
if(i != 0 && pattern[i].y != pattern[i - 1].y && !first_run) {
2019-06-06 06:05:40 +02:00
lv_draw_px(draw_area.x1 - main_line->sx, draw_area.y1, mask, style->line.color, opa);
2018-06-19 09:49:58 +02:00
}
}
#if LV_ANTIALIAS
if(aa) {
lv_draw_aa_ver_seg(prev_p.x + pattern[0].x - aa_shift1, prev_p.y + pattern[0].y,
2019-04-04 07:15:40 +02:00
-(main_line->p_act.y - prev_p.y + 1), mask, style->line.color, opa);
2019-06-06 06:05:40 +02:00
lv_draw_aa_ver_seg(prev_p.x + pattern[width_safe - 1].x + aa_shift2, prev_p.y + pattern[width_safe - 1].y,
2019-04-04 07:15:40 +02:00
main_line->p_act.y - prev_p.y + 1, mask, style->line.color, opa);
}
#endif
2018-06-19 09:49:58 +02:00
}
}
static void line_init(line_draw_t * line, const lv_point_t * p1, const lv_point_t * p2)
{
2018-06-19 09:49:58 +02:00
line->p1.x = p1->x;
line->p1.y = p1->y;
line->p2.x = p2->x;
line->p2.y = p2->y;
2019-04-04 07:15:40 +02:00
line->dx = LV_MATH_ABS(line->p2.x - line->p1.x);
line->sx = line->p1.x < line->p2.x ? 1 : -1;
line->dy = LV_MATH_ABS(line->p2.y - line->p1.y);
line->sy = line->p1.y < line->p2.y ? 1 : -1;
2018-06-19 09:49:58 +02:00
line->err = (line->dx > line->dy ? line->dx : -line->dy) / 2;
2019-04-04 07:15:40 +02:00
line->e2 = 0;
2018-06-19 09:49:58 +02:00
line->hor = line->dx > line->dy ? true : false; /*Rather horizontal or vertical*/
line->p_act.x = line->p1.x;
line->p_act.y = line->p1.y;
}
static bool line_next(line_draw_t * line)
{
2018-06-19 09:49:58 +02:00
if(line->p_act.x == line->p2.x && line->p_act.y == line->p2.y) return false;
line->e2 = line->err;
if(line->e2 > -line->dx) {
line->err -= line->dy;
line->p_act.x += line->sx;
}
if(line->e2 < line->dy) {
line->err += line->dx;
line->p_act.y += line->sy;
}
return true;
}
/**
* Iterate until step one in y direction.
* @param line
* @return
*/
static bool line_next_y(line_draw_t * line)
{
2018-06-19 09:49:58 +02:00
lv_coord_t last_y = line->p_act.y;
2018-06-19 09:49:58 +02:00
do {
if(!line_next(line)) return false;
} while(last_y == line->p_act.y);
2018-06-19 09:49:58 +02:00
return true;
}
/**
* Iterate until step one in x direction.
* @param line
* @return
*/
static bool line_next_x(line_draw_t * line)
{
2018-06-19 09:49:58 +02:00
lv_coord_t last_x = line->p_act.x;
2018-06-19 09:49:58 +02:00
do {
if(!line_next(line)) return false;
} while(last_x == line->p_act.x);
2018-06-19 09:49:58 +02:00
return true;
}