【LVGL笔记】-- 贝塞尔曲线绘制

news2024/11/20 9:46:47

什么是贝塞尔曲线

贝塞尔曲线(Bézier Curve,也被称为贝塞尔多项式(Bézier Polynomial),是由一系列控制点(Control Point)所定义的一条平滑曲线。Pierre Bézier于1960年开始利用该曲线设计雷诺的车身线条,故命名为贝塞尔曲线。目前,贝塞尔曲线被广泛应用于图形设计、路径优化(无人机、无人驾驶相关)等诸多相关领域中。

贝塞尔具体描述,可以搜索,网上也是一大把

贝塞尔曲线之购物车动画效果_11397799的技术博客_51CTO博客

lvgl 贝塞尔函数(三阶函数):

lvgl提供了三阶贝塞尔函数(即四个点绘制图形)

/**
 * Calculate a value of a Cubic Bezier function.
 * @param t time in range of [0..LV_BEZIER_VAL_MAX]
 * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX]
 * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX]
 * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX]
 * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX]
 * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX]
 */

#define LV_BEZIER_VAL_MAX 1024 /**< Max time in Bezier functions (not [0..1] to use integers)*/
#define LV_BEZIER_VAL_SHIFT 10 /**< log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/

uint32_t lv_bezier3(uint32_t t, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3)
{
    uint32_t t_rem  = LV_BEZIER_VAL_MAX - t;
    uint32_t t_rem2 = (t_rem * t_rem) >> 10;
    uint32_t t_rem3 = (t_rem2 * t_rem) >> 10;
    uint32_t t2     = (t * t) >> 10;
    uint32_t t3     = (t2 * t) >> 10;

    uint32_t v1 = (t_rem3 * u0) >> 10;
    uint32_t v2 = (3 * t_rem2 * t * u1) >> 20;
    uint32_t v3 = (3 * t_rem * t2 * u2) >> 20;
    uint32_t v4 = (t3 * u3) >> 10;

    return v1 + v2 + v3 + v4;
}

注:LV_BEZIER_VAL_MAX 参数值为什么定义是:2^n,这里是为了在嵌入式中可以通过移位,优化算法(毕竟做除法运算量是相当大的),另外很多时候分两次移位,因为uint32_t 做乘法的时候精度丢失。

t:(0~LV_BEZIER_VAL_MAX) 可以理解为横坐标

u0,u1,u2,u3 四个点纵坐标

v1 + v2 + v3 + v4: 算出当前绘制点的纵坐标

四阶绘制效果

请添加图片描述

贝塞尔函数(二阶函数):

自己手搓优化的二阶贝塞尔函数
请添加图片描述

转成C语言优化过后如下:

#define LV_BEZIER_VAL_MAX 1024

uint32_t lv_bezier2(uint32_t t, uint32_t u0, uint32_t u1, uint32_t u2)
{
    uint32_t t_rem  = MAX_TIME - t;
    uint32_t t_rem2 = (t_rem * t_rem) >> 10;
    uint32_t t2 = (t * t) >> 10;

    uint32_t v1 = (t_rem2 * u0) >> 10;  
    uint32_t v2 = (2 * u1 * t * t_rem) >> 20;  
    uint32_t v3 = (t2 * u2) >> 10;

    return v1 + v2 + v3;
}

三阶绘制效果

请添加图片描述

绘制代码如下

/**************************************************START OF FILE*****************************************************/






/*------------------------------------------------------------------------------------------------------------------
Includes
*/
#include "xGUI_Page_Eq.h"

/*------------------------------------------------------------------------------------------------------------------
Macros
*/
#define CHART_POINTS_NUM 256

typedef struct
{
    //style list
    bool is_style_init;

    lv_style_t style_src_main;
    lv_style_t style_src_indicator;

    lv_obj_t *pWidgetChart;//[2]; 
    lv_chart_series_t *ser1;//[2];

    lv_obj_t *pWidgetArc[6];
    uint16_t arcPara[6];
}ui_eq_page_manage_t;

/*------------------------------------------------------------------------------------------------------------------
Variables
*/
extern lv_obj_t *pMainWidget;
ui_eq_page_manage_t ui_eq_page_manage;


/*------------------------------------------------------------------------------------------------------------------
Functions
*/
static void eq_style_init(void);
static void refer_chart_cubic_bezier(void);

static void arc_event_callback(lv_event_t * e)
{
	lv_obj_t *obj = lv_event_get_target(e);
	lv_event_code_t event = lv_event_get_code(e);
    uint16_t* puser_data = (uint16_t*)lv_event_get_user_data(e);
    char buf[6];

	if (event == LV_EVENT_VALUE_CHANGED)
	{
		*puser_data = lv_arc_get_value(obj);

        lv_obj_t *label = lv_obj_get_child(obj, NULL);

        lv_snprintf(buf, sizeof(buf), "%d", *puser_data);
        lv_label_set_text(label ,buf);
	}

    refer_chart_cubic_bezier();   
}

/*
********************************************************************************************************************
@ Brief  : 界面显示初始化

@ Param  : None

@ Return : None

@ Author : lyc

@  Date  : 2023 - 01 - 29
********************************************************************************************************************
*/
void gui_eq_init(void)
{
    int i;
    lv_obj_t *label;
    char buf[6];

    pMainWidget = lv_scr_act();
    lv_obj_set_style_bg_color(pMainWidget,lv_palette_darken(LV_PALETTE_GREY,2),0);  

    eq_style_init();

    for(i=0;i<6;i++)
    {
        ui_eq_page_manage.pWidgetArc[i] = lv_arc_create(pMainWidget);
        lv_obj_set_size(ui_eq_page_manage.pWidgetArc[i], 80, 80);
        lv_obj_align(ui_eq_page_manage.pWidgetArc[i],LV_ALIGN_TOP_MID, -300 + 120*i, 350);
        lv_arc_set_bg_angles(ui_eq_page_manage.pWidgetArc[i],135,45);
        lv_arc_set_range(ui_eq_page_manage.pWidgetArc[i], 0, 1024);//256);
        lv_arc_set_value(ui_eq_page_manage.pWidgetArc[i], ui_eq_page_manage.arcPara[i]);
        lv_obj_add_style(ui_eq_page_manage.pWidgetArc[i],&ui_eq_page_manage.style_src_main,LV_PART_MAIN);
        lv_obj_add_style(ui_eq_page_manage.pWidgetArc[i],&ui_eq_page_manage.style_src_indicator,LV_PART_INDICATOR);
        lv_obj_remove_style(ui_eq_page_manage.pWidgetArc[i], NULL, LV_PART_KNOB);

        label = lv_label_create(ui_eq_page_manage.pWidgetArc[i]);
        lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
        lv_obj_set_style_text_color(label, lv_color_white(), LV_PART_MAIN | LV_STATE_DEFAULT);
        //lv_label_set_text(label, "50");
        lv_snprintf(buf, sizeof(buf), "%d", ui_eq_page_manage.arcPara[i]);
        lv_label_set_text(label ,buf);
        lv_obj_add_event_cb(ui_eq_page_manage.pWidgetArc[i],arc_event_callback,LV_EVENT_VALUE_CHANGED,&ui_eq_page_manage.arcPara[i]);  
    }

#if 1
    ui_eq_page_manage.pWidgetChart = lv_chart_create(pMainWidget);
    lv_obj_align(ui_eq_page_manage.pWidgetChart,LV_ALIGN_DEFAULT,0,0);
    lv_obj_set_size(ui_eq_page_manage.pWidgetChart,800,300);
    lv_obj_set_style_pad_all(ui_eq_page_manage.pWidgetChart, 0, LV_PART_MAIN);
    lv_obj_set_style_size(ui_eq_page_manage.pWidgetChart, 0, 0, LV_PART_INDICATOR);
    lv_obj_set_style_bg_color(ui_eq_page_manage.pWidgetChart,lv_palette_darken(LV_PALETTE_GREY,1),LV_PART_MAIN);
    lv_chart_set_type(ui_eq_page_manage.pWidgetChart, LV_CHART_TYPE_SCATTER);
    lv_chart_set_div_line_count(ui_eq_page_manage.pWidgetChart, 11, 5);

    ui_eq_page_manage.ser1 = lv_chart_add_series(ui_eq_page_manage.pWidgetChart, lv_palette_main(LV_PALETTE_AMBER), LV_CHART_AXIS_PRIMARY_Y);
    lv_chart_set_range(ui_eq_page_manage.pWidgetChart, LV_CHART_AXIS_PRIMARY_Y, 0, 1024);   
    lv_chart_set_range(ui_eq_page_manage.pWidgetChart, LV_CHART_AXIS_PRIMARY_X, 0, 1024);   
    lv_chart_set_point_count(ui_eq_page_manage.pWidgetChart, CHART_POINTS_NUM); 
#else
    for(i=0;i<2;i++)
    {
        ui_eq_page_manage.pWidgetChart[i] = lv_chart_create(pMainWidget);
        lv_obj_align(ui_eq_page_manage.pWidgetChart[i],LV_ALIGN_DEFAULT,400*i,0);
        lv_obj_set_size(ui_eq_page_manage.pWidgetChart[i], 400, 300);
        lv_obj_set_style_pad_all(ui_eq_page_manage.pWidgetChart[i], 0, LV_PART_MAIN);
        lv_obj_set_style_size(ui_eq_page_manage.pWidgetChart[i], 0, 0, LV_PART_INDICATOR);
        lv_obj_set_style_bg_color(ui_eq_page_manage.pWidgetChart[i],lv_palette_darken(LV_PALETTE_GREY,1),LV_PART_MAIN);
        lv_obj_set_style_border_width(ui_eq_page_manage.pWidgetChart[i], 0, LV_PART_MAIN);
        lv_chart_set_type(ui_eq_page_manage.pWidgetChart[i], LV_CHART_TYPE_SCATTER);
        ui_eq_page_manage.ser1[i] = lv_chart_add_series(ui_eq_page_manage.pWidgetChart[i], lv_palette_main(LV_PALETTE_AMBER), LV_CHART_AXIS_PRIMARY_Y);
        lv_chart_set_range(ui_eq_page_manage.pWidgetChart[i], LV_CHART_AXIS_PRIMARY_Y, 0, 256);
        lv_chart_set_range(ui_eq_page_manage.pWidgetChart[i], LV_CHART_AXIS_PRIMARY_X, 0, 256);
        lv_chart_set_point_count(ui_eq_page_manage.pWidgetChart[i], 256);
    }
#endif
}

/*
********************************************************************************************************************
@ Brief  : 风格类型初始化:当前界面所有控件的风格整理

@ Param  : None

@ Return : None

@ Author : lyc

@  Date  : 2023 - 01 - 29
********************************************************************************************************************
*/
static void eq_style_init(void)
{
    if(ui_eq_page_manage.is_style_init == false)
    {
        lv_style_init(&ui_eq_page_manage.style_src_main);
        lv_style_set_arc_color(&ui_eq_page_manage.style_src_main,lv_palette_darken(LV_PALETTE_GREY,3));
        lv_style_set_arc_width(&ui_eq_page_manage.style_src_main,8);

        lv_style_init(&ui_eq_page_manage.style_src_indicator);
        lv_style_set_arc_color(&ui_eq_page_manage.style_src_indicator,lv_palette_lighten(LV_PALETTE_ORANGE,1));
        lv_style_set_arc_width(&ui_eq_page_manage.style_src_indicator,8);

        ui_eq_page_manage.is_style_init = true;
    }
}

/*
********************************************************************************************************************
@ Brief  : 贝塞尔二阶函数

@ Param  : None

@ Return : None

@ Author : lyc

@  Date  : 2023 - 02 - 17
********************************************************************************************************************
*/
#define MAX_TIME  (256)
uint32_t lv_bezier2(uint32_t t, uint32_t u0, uint32_t u1, uint32_t u2)
{
    uint32_t t_rem  = MAX_TIME - t;
    uint32_t t_rem2 = (t_rem * t_rem) >> 8;
    uint32_t t2 = (t * t) >> 8;

    uint32_t v1 = (t_rem2 * u0) >> 8;  
    uint32_t v2 = (2 * u1 * t * t_rem) >> 16;  
    uint32_t v3 = (t2 * u2) >> 8;

    return v1 + v2 + v3;
}

static void refer_chart_cubic_bezier(void)
{
    int i;
    int32_t t,step;

#if 1
    for(i = 0; i <= CHART_POINTS_NUM; i ++) 
    {
        uint32_t t = i * (1024 / CHART_POINTS_NUM);
        step = lv_bezier3(t, ui_eq_page_manage.arcPara[0], ui_eq_page_manage.arcPara[1], ui_eq_page_manage.arcPara[2],ui_eq_page_manage.arcPara[3]);
        lv_chart_set_value_by_id2(ui_eq_page_manage.pWidgetChart, ui_eq_page_manage.ser1, i, t, step);
    }
#else
    for(i = 0; i <= CHART_POINTS_NUM; i ++)
    {
        step = lv_bezier2(i, ui_eq_page_manage.arcPara[0], ui_eq_page_manage.arcPara[1], ui_eq_page_manage.arcPara[2]);
        lv_chart_set_value_by_id2(ui_eq_page_manage.pWidgetChart[0], ui_eq_page_manage.ser1[0], i, i, step);
        step = lv_bezier2(i, ui_eq_page_manage.arcPara[2], ui_eq_page_manage.arcPara[3], ui_eq_page_manage.arcPara[4]);
        lv_chart_set_value_by_id2(ui_eq_page_manage.pWidgetChart[1], ui_eq_page_manage.ser1[1], i, i, step);
    }
#endif

    lv_chart_refresh(ui_eq_page_manage.pWidgetChart);
}

/****************************************************END OF FILE*****************************************************/


理解贝塞尔曲线后,可以根据需要搭建多阶算法(阶数越多,曲线拟合更贴切,但算法量越大,对算力较弱的芯片不推荐)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/352380.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

静态代码审计插件 snyk 使用教程

目录 1、vscode 插件安装 2、手动生成 token 3、自动分析 1、vscode 插件安装 2、手动生成 token 点击登录链接:

网站如何锁定用户,超级浏览器有办法解决吗?

随着全球开放&#xff0c;跨境电商人纷纷开启了2023年的搞钱之旅&#xff0c;很多期待着在新的一年大干一场。但前事不忘后事之师&#xff0c;2022年跨境生意全面沦陷&#xff0c;其实除了大环境的因素之外&#xff0c;还有一个很重要的原因是&#xff0c;各个平台都开始实行非…

自己实现strcpy和strlen函数

大家可能会遇到这样的题目&#xff0c;不使用C语言库函数来实现拷贝字符串和求字符串长度的功能。本文就是来详细地说明如何模拟实现这两个函数的功能。 strcpy部分 函数的参数形式char* strcpy(char*destination,const char*source)&#xff1b; 该参数说明了strcpy返回类型…

雅利安人覆灭了世界三大文明,为何单单在商朝被斩首两万?

转自&#xff1a;雅利安人覆灭了世界三大文明&#xff0c;为何单单在商朝被斩首两万&#xff1f; (baidu.com)在公元前3000年至1000年的广大时间内&#xff0c;是世界四大文明古国大放光彩的时候&#xff0c;古印度文明、古巴比伦文明、古埃及文明以及我们的古华夏&#xff0c;…

如何入侵服务器

根据中华人民共和国刑法&#xff1a; 第二百八十六条违反国家规定&#xff0c;对计算机信息系统功能进行删除、修改、增加、干扰&#xff0c;造成计算机信息系统不能正常运行&#xff0c;后果严重的&#xff0c;处五年以下有期徒刑或者拘役&#xff1b;后果特别严重的&#xff…

荧光染料Cyanine5 carboxylic acid,1032678-07-1,花青素Cy5-羧酸

Cyanine5 carboxylic acid&#xff0c;Cy5 COOH&#xff0c;Cyanine5 COOH| 花青素Cy5-羧酸&#xff0c;花青素Cyanine5羧酸 | CAS&#xff1a;1032678-07-1 | 纯度&#xff1a;95%试剂信息&#xff1a;CAS&#xff1a;1032678-07-1外观&#xff1a;深蓝粉末分子量&#xff1a;…

LeetCode 周赛 332,在套路里摸爬滚打~

本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 提问。 大家好&#xff0c;今天是 3T 选手小彭。 上周是 LeetCode 第 332 场周赛&#xff0c;你参加了吗&#xff1f;算法解题思维需要长时间锻炼&#xff0c;加入我们一起刷题吧~ 小…

2023,再转行去做软件测试还有前途吗?

近年来&#xff0c;以云计算、移动互联网、物联网、工业互联网、人工智能、大数据及区块链等新一代信息技术构建的智能化应用和产品出现爆发式增长&#xff0c;突破了传统对于软件形态的认知&#xff0c;软件形态正以各种展现方式诠释着对新型智能软件的定义。这也使得软件的质…

Java提供了哪些IO方式? NIO如何实现多路复用?

第11讲 | Java提供了哪些IO方式&#xff1f; NIO如何实现多路复用&#xff1f; IO 一直是软件开发中的核心部分之一&#xff0c;伴随着海量数据增长和分布式系统的发展&#xff0c;IO 扩展能力愈发重要。幸运的是&#xff0c;Java 平台 IO 机制经过不断完善&#xff0c;虽然在某…

项目管理工具dhtmlxGantt甘特图入门教程(十):服务器端数据集成(上)

这篇文章给大家讲解如何利用dhtmlxGantt在服务器端集成数据。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足应用程序的所有需求&#xff0c;是完善的甘特图图表库 DhtmlxGantt正版试用下载&#xff08;qun&#xff1a;764148812&#…

考前梳理:PMP®备考之敏捷实践中的五大事件

今天为大家总结了PMP敏捷实践中的五大事件&#xff0c;帮助大家回顾考试重点&#xff0c;大家可以看着下方敏捷实践流程图进行个人构思&#xff0c;后文也会为大家一一剖析其中的重要环节。完整的Scrum敏捷实践框架流程图&#xff1a;一、冲刺计划会议 Sprint Planning1.为即将…

SQP求解器推导与matlab命令(JacobianHessian矩阵)

缩写&#xff1a; SQP(Sequential Quadratic Programming)序列二次规划 NLP 非线性规划问题 matlab代码 matlab中求解器 SQP的认识 《最优化方法及其Matlab程序设计》 书 马昌凤 SQP 知乎 基础知识点 I.Jacobian矩阵 Def: 一阶偏导 II.Hessian矩阵 Def: 二阶偏导 图 三阶…

【SpringCloud+Vue】生成微信二维码及扫码登录--OAuth2

OAuth2 微信登录流程 前端代码实现 后端代码实现 导入依赖 yml 实体类以及返回结果 工具类 微信配置信息 HTTP客户端连接池 JWT 控制层 业务层 持久层 OAuth2 OAuth2是OAuth&#xff08;Open Authorization&#xff0c;开放授权&#xff09;协议的延续版本。用来授…

Hinge Loss 和 Zero-One Loss

文章目录Hinge Loss 和 Zero-One LossHinge LossZero-One LossHinge Loss 和 Zero-One Loss 维基百科&#xff1a;https://en.wikipedia.org/wiki/Hinge_loss 图表说明&#xff1a; 纵轴表示固定 t1t1t1 的 Hinge loss&#xff08;蓝色&#xff09;和 Zero-One Loss&#xff…

字节5年测试经验,12月无情被辞,划水的兄弟别再这样了····

前言 先简单交代一下背景吧&#xff0c;某不知名 985 的本硕&#xff0c;17 年毕业加入字节&#xff0c;以“人员优化”的名义无情被裁员&#xff0c;之后跳槽到了有赞&#xff0c;一直从事软件测试的工作。之前没有实习经历&#xff0c;算是5年的工作经验吧。 这5年之间完成…

实现一个小程序分享图 wxml2canvas

我们经常会遇上动态生成海报的需求&#xff0c;而在小程序中&#xff0c;生成图片非Canvas莫属。但是在实际工作当中&#xff0c;为了追求效率&#xff0c;我们会不可避免地去使用一些JS插件&#xff0c;而 wxml-to-canvas 就是一款官方推荐且非常优秀的插件&#xff0c;它可以…

图文详解Ansible中的变量及加密

文章目录一、变量命名二、变量级别三、.变量设定和使用方式1.在playbook中直接定义变量2.在文件中定义变量3.使用变量4.设定主机变量和清单变量5.目录设定变量6.用命令覆盖变量7.使用数组设定变量8.注册变量9.事实变量10.魔法变量四、JINJA2模板五、 Ansible的加密控制练习1.用…

I2C总线应用测试程序

参考链接&#xff1a;I2c协议 Linux I2C应用编程开发 问题背景 在工作中需要测试I2C总线的传输稳定性&#xff0c;需写一个测试程序通过读写从设备寄存器的值来验证数据传输稳定性。 站在cpu的角度来看&#xff0c;操作I2C外设实际上就是通过控制cpu中挂载该I2C外设的I2C控制…

yunUI组件库解析:图片上传与排序组件yImgPro

yunUI是笔者开源的微信小程序功能库。目前其中包含了一些复杂的功能组件。方便使用。未来它将分为组件、样式、js三者合为一体&#xff0c;但分别提供。 本文所用代码皆来源于组件库中的yImgPro组件。详细代码可至github查看。地址&#xff1a; yunUI 。 npm地址&#xff1a;yu…

Bing+ChatGPT 对传统搜索引擎的降维打击

早些时候申请了新版 Bing 的内测资格&#xff0c;终于收到了通过的邮件。 一天的体验之后&#xff0c;我的感受是&#xff1a;当新版 Bing 具备了 ChatGPT 的聊天能力之后&#xff0c;它的能力不论是对传统搜索引擎&#xff0c;还是 ChatGPT 自身&#xff0c;都将是降维打击。 …