feat(vector): add API to append arc (#5510)

Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
This commit is contained in:
Neo Xu
2024-01-30 17:33:10 +08:00
committed by GitHub
parent 61b8378286
commit e4de2d265a
6 changed files with 174 additions and 1 deletions
+32 -1
View File
@@ -189,6 +189,37 @@ static void draw_blend(lv_vector_dsc_t * ctx, lv_vector_path_t * path)
lv_vector_dsc_add_path(ctx, path); // draw a path
}
static void draw_arc(lv_vector_dsc_t * ctx, lv_vector_path_t * path)
{
lv_vector_path_clear(path);
lv_vector_dsc_identity(ctx);
lv_area_t rect = {100, 0, 150, 50};
lv_vector_dsc_set_fill_color(ctx, lv_color_lighten(lv_color_black(), 50));
lv_vector_clear_area(ctx, &rect); // clear screen
lv_fpoint_t p = {100, 50}; /* Center */
lv_vector_dsc_set_stroke_color(ctx, lv_color_make(0x00, 0xff, 0xff));
lv_vector_dsc_set_stroke_opa(ctx, LV_OPA_COVER);
lv_vector_dsc_set_stroke_width(ctx, 2.0f);
lv_vector_dsc_set_stroke_dash(ctx, NULL, 0);
lv_vector_dsc_set_fill_color32(ctx, lv_color32_make(0xFF, 0x00, 0x00, 0x80));
lv_vector_path_move_to(path, &p);
lv_fpoint_t temp = {p.x + 50, p.y};
lv_vector_path_line_to(path, &temp);
lv_vector_path_append_arc(path, &p, 50, 0, -90, false);
lv_vector_path_line_to(path, &p);
lv_vector_path_close(path);
lv_vector_dsc_add_path(ctx, path);
/* Below code has same effect as above one. */
lv_vector_path_clear(path);
lv_vector_path_append_arc(path, &p, 50, 45, 45, true);
lv_vector_dsc_add_path(ctx, path); // draw a path
}
static void draw_vector(lv_layer_t * layer)
{
lv_vector_dsc_t * ctx = lv_vector_dsc_create(layer);
@@ -205,7 +236,7 @@ static void draw_vector(lv_layer_t * layer)
draw_radial_gradient(ctx, path);
draw_gradient(ctx, path);
draw_blend(ctx, path);
draw_arc(ctx, path);
lv_draw_vector(ctx); // submit draw
lv_vector_path_delete(path);
lv_vector_dsc_delete(ctx);
+2
View File
@@ -47,3 +47,5 @@
--exclude=../tests/unity/unity_support.c
--exclude=../tests/unity/unity_support.h
--exclude=../tests/test_images
--exclude=../tests/build_test_defheap
--exclude=../tests/build_test_sysheap
+96
View File
@@ -14,6 +14,16 @@
#include "../stdlib/lv_string.h"
#include <stdbool.h>
#include <math.h>
#include <float.h>
#define MATH_PI 3.14159265358979323846f
#define MATH_HALF_PI 1.57079632679489661923f
#define DEG_TO_RAD 0.017453292519943295769236907684886f
#define RAD_TO_DEG 57.295779513082320876798154814105f
#define MATH_RADIANS(deg) ((deg) * DEG_TO_RAD)
#define MATH_DEGRESS(rad) ((rad) * RAD_TO_DEG)
/*********************
* DEFINES
@@ -470,6 +480,92 @@ void lv_vector_path_append_circle(lv_vector_path_t * path, const lv_fpoint_t * c
lv_vector_path_close(path);
}
/**
* Add a arc to the path
* @param path pointer to a path
* @param c pointer to a `lv_fpoint_t` variable for center of the circle
* @param radius the radius for arc
* @param start_angle the start angle for arc
* @param sweep the sweep angle for arc, could be negative
* @param pie true: draw a pie, false: draw a arc
*/
void lv_vector_path_append_arc(lv_vector_path_t * path, const lv_fpoint_t * c, float radius, float start_angle,
float sweep, bool pie)
{
float cx = c->x;
float cy = c->y;
/* just circle */
if(sweep >= 360.0f || sweep <= -360.0f) {
lv_vector_path_append_circle(path, c, radius, radius);
return;
}
start_angle = MATH_RADIANS(start_angle);
sweep = MATH_RADIANS(sweep);
int n_curves = (int)ceil(fabsf(sweep / MATH_HALF_PI));
float sweep_sign = sweep < 0 ? -1.f : 1.f;
float fract = fmodf(sweep, MATH_HALF_PI);
fract = (fabsf(fract) < FLT_EPSILON) ? MATH_HALF_PI * sweep_sign : fract;
/* Start from here */
lv_fpoint_t start = {
.x = radius * cosf(start_angle),
.y = radius * sinf(start_angle),
};
if(pie) {
lv_vector_path_move_to(path, &(lv_fpoint_t) {
cx, cy
});
lv_vector_path_line_to(path, &(lv_fpoint_t) {
start.x + cx, start.y + cy
});
}
else {
lv_vector_path_move_to(path, &(lv_fpoint_t) {
start.x + cx, start.y + cy
});
}
for(int i = 0; i < n_curves; ++i) {
float end_angle = start_angle + ((i != n_curves - 1) ? MATH_HALF_PI * sweep_sign : fract);
float end_x = radius * cosf(end_angle);
float end_y = radius * sinf(end_angle);
/* variables needed to calculate bezier control points */
/** get bezier control points using article:
* (http://itc.ktu.lt/index.php/ITC/article/view/11812/6479)
*/
float ax = start.x;
float ay = start.y;
float bx = end_x;
float by = end_y;
float q1 = ax * ax + ay * ay;
float q2 = ax * bx + ay * by + q1;
float k2 = (4.0f / 3.0f) * ((sqrtf(2 * q1 * q2) - q2) / (ax * by - ay * bx));
/* Next start point is the current end point */
start.x = end_x;
start.y = end_y;
end_x += cx;
end_y += cy;
lv_fpoint_t ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy};
lv_fpoint_t ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy};
lv_fpoint_t end = {end_x, end_y};
lv_vector_path_cubic_to(path, &ctrl1, &ctrl2, &end);
start_angle = end_angle;
}
if(pie) {
lv_vector_path_close(path);
}
}
void lv_vector_path_append_path(lv_vector_path_t * path, const lv_vector_path_t * subpath)
{
uint32_t ops_size = lv_array_size(&path->ops);
+12
View File
@@ -308,6 +308,18 @@ void lv_vector_path_append_rect(lv_vector_path_t * path, const lv_area_t * rect,
*/
void lv_vector_path_append_circle(lv_vector_path_t * path, const lv_fpoint_t * c, float rx, float ry);
/**
* Add a arc to the path
* @param path pointer to a path
* @param c pointer to a `lv_fpoint_t` variable for center of the circle
* @param radius the radius for arc
* @param start_angle the start angle for arc
* @param sweep the sweep angle for arc, could be negative
* @param pie true: draw a pie, false: draw a arc
*/
void lv_vector_path_append_arc(lv_vector_path_t * path, const lv_fpoint_t * c, float radius, float start_angle,
float sweep, bool pie);
/**
* Add an sub path to the path
* @param path pointer to a path
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

@@ -94,6 +94,38 @@ static void draw_shapes(lv_layer_t * layer)
lv_vector_dsc_set_fill_rule(ctx, LV_VECTOR_FILL_EVENODD);
lv_vector_dsc_add_path(ctx, path);
lv_vector_path_clear(path);
lv_vector_dsc_identity(ctx);
lv_vector_dsc_set_blend_mode(ctx, LV_VECTOR_BLEND_SRC_OVER);
rect = (lv_area_t) {
500, 50, 550, 100
};
lv_vector_dsc_set_fill_color(ctx, lv_color_lighten(lv_color_black(), 50));
lv_vector_clear_area(ctx, &rect); // clear screen
lv_fpoint_t p = {500, 100}; /* Center */
lv_vector_dsc_set_stroke_color(ctx, lv_color_make(0x00, 0xff, 0xff));
lv_vector_dsc_set_stroke_opa(ctx, LV_OPA_COVER);
lv_vector_dsc_set_stroke_width(ctx, 2.0f);
lv_vector_dsc_set_stroke_dash(ctx, NULL, 0);
lv_vector_dsc_set_fill_opa(ctx, LV_OPA_TRANSP);
lv_vector_path_move_to(path, &p);
lv_fpoint_t temp = {p.x + 50, p.y};
lv_vector_path_line_to(path, &temp);
lv_vector_path_append_arc(path, &p, 50, 0, -90, false);
lv_vector_path_line_to(path, &p);
lv_vector_path_close(path);
lv_vector_dsc_add_path(ctx, path);
/* Below code has same effect as above one but with solid fill */
lv_vector_dsc_set_fill_color(ctx, lv_color_make(0xFF, 0x00, 0x00));
lv_vector_dsc_set_fill_opa(ctx, LV_OPA_COVER);
lv_vector_path_clear(path);
lv_vector_path_append_arc(path, &p, 50, 45, 45, true);
lv_vector_dsc_add_path(ctx, path); // draw a path
lv_draw_vector(ctx);
lv_vector_path_delete(path);
lv_vector_dsc_delete(ctx);