【C语言】贝塞尔曲线

// 画贝塞尔曲线的函数 pointTag 结构体
struct pointTag
{
	double x, y;
};
void DrawBezierCurve(uint32_t lineColor, int len, ...)
{
	if (len <= 1)
	{
		//不支持单点线
		return;
	}

	va_list list;
	va_start(list, len);
	pointTag* temp = (pointTag*)malloc((len) * sizeof(pointTag));
	for (int i = 0; i < len; i++)
	{
		temp[i] = va_arg(list, pointTag);
	}
	va_end(list);


	pointTag* parent = NULL, * child = NULL;
	pointTag lastPoint = temp[0];

	for (double lineNum = 0; lineNum < 1 + 1.0 / 100; lineNum += 1.0 / 100)
	{
		int size = len;
		parent = temp;
		while (size > 1)
		{
			child = (pointTag*)malloc((size - 1) * sizeof(pointTag));
			for (int i = 0; i < size - 1; i++)
			{
				child[i].x = parent[i].x + (parent[i + 1].x - parent[i].x) * lineNum;
				child[i].y = parent[i].y + (parent[i + 1].y - parent[i].y) * lineNum;
			}
			if (parent != temp)
			{
				free(parent);
			}
			parent = child;
			size--;
		}
		//自定义两点画线函数
		QUI_Line(lastPoint.x, lastPoint.y, parent->x, parent->y, lineColor);

		lastPoint.x = parent->x;
		lastPoint.y = parent->y;
		free(parent);
		parent = NULL;
		child = NULL;
	}
	free(temp);
}


void DrawBezierCurve_Test()
{
	//测试5个点形成的贝塞尔
	pointTag p1 = { 50, 30 };
	pointTag p2 = { 150, 280 };
	pointTag p3 = { 200, 160 };
	pointTag p4 = { 250, 140 };
	pointTag p5 = { 300, 200 };
	DrawBezierCurve(RED, 5, p1, p2, p3, p4, p5);
	UpdateScreen();//自定义刷屏函数
}

//LVGL工具下的3阶贝塞尔(带图表chart)测试方案
/*
PS:chart线去掉圆点的方法:
lv_chart.c 中 static void draw_series_line(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx)函数里将
lv_coord_t point_w = lv_obj_get_style_width(obj, LV_PART_INDICATOR) / 2;
lv_coord_t point_h = lv_obj_get_style_height(obj, LV_PART_INDICATOR) / 2;
改为
lv_coord_t point_w = 0;
lv_coord_t point_h = 0;
*/

#define USER_CHART_EFFECT  1

#define CHART_X_MAX 1024
#define CHART_Y_MAX 1024

static int CHART_POINTS_NUM = 32;//要根据屏幕分辨率来按比例设定,推荐=SCEEN_Y/10

struct {
    lv_obj_t* chart;
    lv_chart_series_t* ser;
    uint16_t p0;//start_point_Y
    uint16_t p1;
    uint16_t p2;
    uint16_t p3;//end_point_Y
  
} g_myBezier;


void set_new_pointY(uint16_t y0, uint16_t y1, uint16_t y2, uint16_t y3 )
{
    g_myBezier.p0 = y0;
    g_myBezier.p1 = y1;
    g_myBezier.p2 = y2;
    g_myBezier.p3 = y3;
}

static void update_bezier_curve(void)
{
 
    for (uint16_t i = 0; i <= CHART_POINTS_NUM; i++) {
        uint32_t t = i * (CHART_X_MAX / CHART_POINTS_NUM); //x_data
        int32_t step =lv_bezier3(t, g_myBezier.p0, g_myBezier.p1, g_myBezier.p2, g_myBezier.p3);//y_data
        lv_chart_set_value_by_id2(g_myBezier.chart, g_myBezier.ser, i, t, step);//id = group data index
        // printf("[%d] t = %d , step = %d . \n", i, t, step);
    }
}


static void draw_event_cb(lv_event_t* e)
{
    lv_obj_t* obj = lv_event_get_target(e);

#if (USER_CHART_EFFECT!=1)
    return;
#endif // (USER_CHART_EFFECT!=1)


    /*Add the faded area before the lines are drawn*/
    lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
    if (dsc->part == LV_PART_ITEMS) {
        if (!dsc->p1 || !dsc->p2) return;

        /*Add a line mask that keeps the area below the line*/
        lv_draw_mask_line_param_t line_mask_param;
        lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y,
            LV_DRAW_MASK_LINE_SIDE_BOTTOM);
        int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);

        //Add a fade effect: transparent bottom covering top
        lv_coord_t h = lv_obj_get_height(obj);
        lv_draw_mask_fade_param_t fade_mask_param;
        lv_draw_mask_fade_init(&fade_mask_param, &obj->coords, LV_OPA_COVER, obj->coords.y1 + h / 8, LV_OPA_TRANSP,
            obj->coords.y2);
        int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL);

        //Draw a rectangle that will be affected by the mask
        lv_draw_rect_dsc_t draw_rect_dsc;
        lv_draw_rect_dsc_init(&draw_rect_dsc);
        draw_rect_dsc.bg_opa = LV_OPA_80;//20
        draw_rect_dsc.bg_color = dsc->line_dsc->color;

        lv_area_t a;
        a.x1 = dsc->p1->x;
        a.x2 = dsc->p2->x - 1;
        a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
        a.y2 = obj->coords.y2;
        lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

        //Remove the masks
        lv_draw_mask_free_param(&line_mask_param);
        lv_draw_mask_free_param(&fade_mask_param);
        lv_draw_mask_remove_id(line_mask_id);
        lv_draw_mask_remove_id(fade_mask_id);
           
    }

}



static void lv_bezier_curve_init(void)
{
    /*Create a Bezier.chart*/
    g_myBezier.chart = lv_chart_create(lv_scr_act());

    lv_obj_set_size(g_myBezier.chart, 480, 320); //480*320
    lv_obj_center(g_myBezier.chart);

   // lv_chart_set_type(g_myBezier.chart, LV_CHART_TYPE_LINE);   /*Show lines and points too*/
    lv_chart_set_type(g_myBezier.chart, LV_CHART_TYPE_SCATTER);

    lv_chart_set_range(g_myBezier.chart, LV_CHART_AXIS_PRIMARY_Y, 0, CHART_Y_MAX);
    lv_chart_set_range(g_myBezier.chart, LV_CHART_AXIS_PRIMARY_X, 0, CHART_X_MAX);
    lv_chart_set_point_count(g_myBezier.chart, CHART_POINTS_NUM);

    lv_chart_set_div_line_count(g_myBezier.chart, 0,4);//(0,0)=>hide the chart background

    lv_obj_add_event_cb(g_myBezier.chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
    lv_chart_set_update_mode(g_myBezier.chart, LV_CHART_UPDATE_MODE_CIRCULAR);

    /*Add data series*/
    g_myBezier.ser = lv_chart_add_series(g_myBezier.chart,lv_color_hex(0x00ff00), LV_CHART_AXIS_PRIMARY_Y); //lv_palette_main(LV_PALETTE_RED)
    update_bezier_curve();

}


void my_timer(lv_timer_t* timer)
{
    /*Do something with LVGL*/
    static int cnt = 0;
    printf("Run_cnt=[%d].\n",cnt++);
    set_new_pointY(lv_rand(0, CHART_Y_MAX), lv_rand(0, CHART_Y_MAX), lv_rand(0, CHART_Y_MAX), lv_rand(0, CHART_Y_MAX) );
    update_bezier_curve();
}


void MAIN()
{
    lv_bezier_curve_init();
    lv_timer_t* timer = lv_timer_create(my_timer, 1500, NULL);
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值