【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);
}

<think>好的,用户想找用C语言实现贝塞尔曲线的代码示例。我先看看用户提供的引用内容。引用[1]里有一个二次贝塞尔曲线的C代码,看起来可以直接用。用户可能需要的是不同阶数的贝塞尔曲线,比如三次的,但示例里是二次的。那我可以先展示二次的,然后如果有需要再扩展到三次的。 接下来,用户可能想知道贝塞尔曲线的基本原理,所以需要解释一下参数方程。二次贝塞尔的方程是$(1-t)^2 P0 + 2t(1-t) P1 + t^2 P2$,对吧?在代码里,用户给出的例子是三个控制点,所以二次是对的。那三次的话可能需要四个控制点,方程也会不同,但用户的问题没有提到三次,所以可能暂时不需要。 然后,代码中的循环是t从0到1,步长0.01,这样足够精细吗?可能用户需要调整步长,可以建议根据需要修改。另外,代码里的计算方式是否正确?是的,每个坐标都是根据t值计算的,然后打印出来。 用户可能还想知道如何应用这个代码,比如在图形库中绘制,但引用里的代码只是打印坐标,可能需要结合具体的图形库,比如OpenGL。不过用户的问题只是要C语言的示例,所以保持控制台输出就可以了。 另外,引用[2]提到贝塞尔曲线分割的问题,用户可能对高级应用感兴趣,但当前问题只需要实现代码,所以可能不需要深入讨论分割方法,但可以作为相关问题提出。 最后,确保代码正确,没有语法错误,比如变量名是否正确,循环是否正确。用户提供的示例代码看起来没问题,可以原样呈现。可能还需要说明如何编译运行,比如使用gcc编译器。 总结:提供二次贝塞尔的C代码,解释参数方程,说明控制点,并提示三次贝塞尔的扩展方法。生成相关问题时,可以包括性能优化、分割曲线、图形库应用等。</think>根据您的要求,我将为您展示C语言实现二次贝塞尔曲线的完整代码,并解释其数学原理和实现步骤。 ### 一、二次贝塞尔曲线实现 #### 1. 数学原理 二次贝塞尔曲线由三个控制点$P_1(x_1,y_1)$(起点)、$P_2(x_2,y_2)$(控制点)、$P_3(x_3,y_3)$(终点)定义,参数方程: $$ B(t) = (1-t)^2P_1 + 2t(1-t)P_2 + t^2P_3 $$ 其中$t \in [0,1]$,对应曲线离散点的坐标计算方式: $$ \begin{cases} x(t) = (1-t)^2x_1 + 2t(1-t)x_2 + t^2x_3 \\ y(t) = (1-t)^2y_1 + 2t(1-t)y_2 + t^2y_3 \end{cases} $$ #### 2. 代码实现 ```c #include <stdio.h> void drawQuadraticBezier(int x1, int y1, int x2, int y2, int x3, int y3) { const float step = 0.01; // 精度控制 for (float t = 0; t <= 1; t += step) { // 计算混合系数 float mt = 1 - t; float coeff1 = mt * mt; float coeff2 = 2 * mt * t; float coeff3 = t * t; // 计算坐标值 int x = coeff1 * x1 + coeff2 * x2 + coeff3 * x3; int y = coeff1 * y1 + coeff2 * y2 + coeff3 * y3; printf("绘制点坐标: (%d, %d)\n", x, y); } } int main() { // 设置控制点坐标(起点、控制点、终点) drawQuadraticBezier(100, 100, 200, 300, 300, 100); return 0; } ``` #### 3. 代码说明 - 参数`step`控制曲线精度,值越小曲线越平滑[^1] - 使用浮点运算保证插值精度 - 输出结果可直接用于控制台绘图或结合图形库使用 ### 二、三次贝塞尔曲线扩展 三次贝塞尔曲线需要四个控制点,参数方程为: $$ B(t) = (1-t)^3P_1 + 3t(1-t)^2P_2 + 3t^2(1-t)P_3 + t^3P_4 $$ 实现时只需扩展计算逻辑: ```c float coeff1 = (1-t)*(1-t)*(1-t); float coeff2 = 3*t*(1-t)*(1-t); float coeff3 = 3*t*t*(1-t); float coeff4 = t*t*t; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值