贝塞尔曲线二(一次到五次)

2024-03-15 12:28
文章标签 一次 贝塞尔 曲线 五次

本文主要是介绍贝塞尔曲线二(一次到五次),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、三次贝塞尔曲线

三次贝塞尔曲线是更复杂的曲线形式,它由四个点定义:起始点 P0、两个控制点 P1 和 P2 以及结束点 P3。曲线上的任意一点 B(t) 可以通过以下公式计算:

B(t) = (1 - t)^3 * P0 + 3 * (1 - t)^2 * t * P1 + 3 * (1 - t) * t^2 * P2 + t^3 * P3

其中 t 是参数,取值范围是 [0, 1]。
推导三次贝塞尔曲线的过程可以从一次和二次贝塞尔曲线的推广出发。我们已经知道,一次贝塞尔曲线是两点之间的线性插值,而二次贝塞尔曲线是两点之间受一个控制点影响的曲线。三次贝塞尔曲线可以看作是两点之间受两个控制点影响的曲线。
为了推导三次贝塞尔曲线,我们可以采用递归的思想,即使用二次贝塞尔曲线来构造三次贝塞尔曲线。具体步骤如下:

  1. 在起始点 P0 和控制点 P1 之间构造一条二次贝塞尔曲线。
  2. 在控制点 P1 和控制点 P2 之间构造一条二次贝塞尔曲线。
  3. 在控制点 P2 和结束点 P3 之间构造一条二次贝塞尔曲线。
  4. 然后在这些二次贝塞尔曲线之间进行插值。
    设 t 为参数,我们可以定义三个中间点 R0、R1 和 R2,它们分别是在 t = 0、t = 0.5 和 t = 1 时,上述三条二次贝塞尔曲线上的点。然后,我们在 R0 和 R1 之间、R1 和 R2 之间分别构造一次贝塞尔曲线。

最后,我们在这些一次贝塞尔曲线之间进行插值,得到最终的三次贝塞尔曲线上的点 B(t)。通过这种方式,我们可以得到三次贝塞尔曲线的公式:

B(t) = (1 - t)^3 * P0 + 3 * (1 - t)^2 * t * P1 + 3 * (1 - t) * t^2 * P2 + t^3 * P3

这就是三次贝塞尔曲线的推导过程。通过这种方式,我们可以看到三次贝塞尔曲线是如何从一次和二次贝塞尔曲线的基础上构造出来的,同时也揭示了控制点 P1 和 P2 如何影响曲线的形状。三次贝塞尔曲线在计算机图形学中非常有用,因为它提供了一种灵活的方式来绘制复杂的曲线形状。
以下是一个使用SDL2库的C语言程序,它实现了三次贝塞尔曲线的可视化:

#include <SDL.h>
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600// 定义一个结构体来表示一个点
typedef struct {float x;float y;
} Point;// 计算三次贝塞尔曲线上的点
Point calculateBezierPoint(Point p0, Point p1, Point p2, Point p3, float t) {Point p;float u = 1 - t;float tt = t * t;float uu = u * u;float uuu = uu * u;float ttt = tt * t;p.x = uuu * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + ttt * p3.x;p.y = uuu * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + ttt * p3.y;return p;
}int main(int argc, char* args[]) {SDL_Window* window = NULL;SDL_Renderer* renderer = NULL;if (SDL_Init(SDL_INIT_VIDEO) < 0) {printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());return 1;}window = SDL_CreateWindow("Bezier Curve Visualization", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);if (window == NULL) {printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());return 1;}renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);if (renderer == NULL) {printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());return 1;}SDL_Event e;bool quit = false;while (!quit) {while (SDL_PollEvent(&e) != 0) {if (e.type == SDL_QUIT) {quit = true;}}SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);SDL_RenderClear(renderer);// 定义四个控制点Point p0 = {100.0, 500.0};Point p1 = {300.0, 100.0};Point p2 = {500.0, 500.0};Point p3 = {700.0, 100.0};// 绘制控制点SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);SDL_RenderDrawPoint(renderer, (int)p0.x, (int)p0.y);SDL_RenderDrawPoint(renderer, (int)p1.x, (int)p1.y);SDL_RenderDrawPoint(renderer, (int)p2.x, (int)p2.y);SDL_RenderDrawPoint(renderer, (int)p3.x, (int)p3.y);// 绘制三次贝塞尔曲线SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);Point prev = p0;for (float t = 0.01; t <= 1.0; t += 0.01) {Point current = calculateBezierPoint(p0, p1, p2, p3, t);SDL_RenderDrawLine(renderer, (int)prev.x, (int)prev.y, (int)current.x, (int)current.y);prev = current;}SDL_RenderPresent(renderer);}SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return 0;
}

在这个程序中,我们首先初始化SDL,创建一个窗口和渲染器。然后,我们进入一个事件循环,监听退出事件。在每次循环中,我们清除屏幕,绘制四个控制点,并使用calculateBezierPoint函数绘制三次贝塞尔曲线。

二、四次贝塞尔曲线

四次贝塞尔曲线是由五个点定义的曲线,这五个点包括一个起始点、三个控制点和一个结束点。四次贝塞尔曲线的方程是:

B(t) = (1 - t)^4 * P0 + 4 * (1 - t)^3 * t * P1 + 6 * (1 - t)^2 * t^2 * P2 + 4 * (1 - t) * t^3 * P3 + t^4 * P4

其中 t 是参数,取值范围是 [0, 1],P0 是起始点,P1、P2 和 P3 是控制点,P4 是结束点。B(t) 表示曲线上 t 时刻的点的坐标。
四次贝塞尔曲线的推导过程可以通过递归的思想来进行,即使用更低次的贝塞尔曲线来构造更高次的曲线。具体来说,我们可以使用三次贝塞尔曲线来构造四次贝塞尔曲线。
假设我们有四个三次贝塞尔曲线,它们的控制点分别是:

  1. P0, P1, P2, P3
  2. P1, P2, P3, P4
  3. P2, P3, P4, Q (一个临时点)
  4. P3, P4, Q, Q
    我们可以看到,这四个三次贝塞尔曲线共享了 P2 和 P3 这两个控制点。我们可以在这四个三次贝塞尔曲线之间进行插值,以得到最终的四次贝塞尔曲线。
    设 t 为参数,我们可以定义三个中间点 R0、R1 和 R2,它们分别是在 t = 0、t = 1/3 和 t = 2/3 时,上述四个三次贝塞尔曲线上的点。然后,我们在 R0 和 R1 之间、R1 和 R2 之间、R2 和 Q 之间分别构造二次贝塞尔曲线。

最后,我们在这些二次贝塞尔曲线之间进行插值,得到最终的四次贝塞尔曲线上的点 B(t)。通过这种方式,我们可以得到四次贝塞尔曲线的公式:

B(t) = (1 - t)^4 * P0 + 4 * (1 - t)^3 * t * P1 + 6 * (1 - t)^2 * t^2 * P2 + 4 * (1 - t) * t^3 * P3 + t^4 * P4

这就是四次贝塞尔曲线的推导过程。通过这种方式,我们可以看到四次贝塞尔曲线是如何从三次贝塞尔曲线的基础上构造出来的,同时也揭示了控制点 P1、P2 和 P3 如何影响曲线的形状。四次贝塞尔曲线在计算机图形学中非常有用,因为它提供了一种灵活的方式来绘制复杂的曲线形状。

#include <SDL.h>
#include <stdio.h>
#include <math.h>#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600// 定义一个结构体来表示一个点
typedef struct {float x;float y;
} Point;// 计算四次贝塞尔曲线上的点
Point calculateBezierPoint(Point p0, Point p1, Point p2, Point p3, Point p4, float t) {Point p;float u = 1 - t;float tt = t * t;float uu = u * u;float uuu = uu * u;float ttt = tt * t;p.x = uuu * u * p0.x + 4 * uuu * t * p1.x + 6 * uu * tt * p2.x + 4 * u * ttt * p3.x + ttt * t * p4.x;p.y = uuu * u * p0.y + 4 * uuu * t * p1.y + 6 * uu * tt * p2.y + 4 * u * ttt * p3.y + ttt * t * p4.y;return p;
}int main(int argc, char* args[]) {SDL_Window* window = NULL;SDL_Renderer* renderer = NULL;if (SDL_Init(SDL_INIT_VIDEO) < 0) {printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());return 1;}window = SDL_CreateWindow("Bezier Curve Visualization", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);if (window == NULL) {printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());return 1;}renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);if (renderer == NULL) {printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());return 1;}SDL_Event e;bool quit = false;while (!quit) {while (SDL_PollEvent(&e) != 0) {if (e.type == SDL_QUIT) {quit = true;}}SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);SDL_RenderClear(renderer);// 定义五个控制点Point p0 = {100.0, 500.0};Point p1 = {200.0, 100.0};Point p2 = {400.0, 100.0};Point p3 = {600.0, 500.0};Point p4 = {700.0, 100.0};// 绘制控制点SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);SDL_RenderDrawPoint(renderer, (int)p0.x, (int)p0.y);SDL_RenderDrawPoint(renderer, (int)p1.x, (int)p1.y);SDL_RenderDrawPoint(renderer, (int)p2.x, (int)p2.y);SDL_RenderDrawPoint(renderer, (int)p3.x, (int)p3.y);SDL_RenderDrawPoint(renderer, (int)p4.x, (int)p4.y);// 绘制四次贝塞尔曲线SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);Point prev = p0;for (float t = 0.01; t <= 1.0; t += 0.01) {Point current = calculateBezierPoint(p0, p1, p2, p3, p4, t);SDL_RenderDrawLine(renderer, (int)prev.x, (int)prev.y, (int)current.x, (int)current.y);prev = current;}SDL_RenderPresent(renderer);}SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return 0;
}

三、五次贝塞尔曲线

五次贝塞尔曲线是由六个点定义的曲线,这六个点包括一个起始点、四个控制点和一个结束点。五次贝塞尔曲线的方程是:

B(t) = (1 - t)^5 * P0 + 5 * (1 - t)^4 * t * P1 + 10 * (1 - t)^3 * t^2 * P2 + 10 * (1 - t)^2 * t^3 * P3 + 5 * (1 - t) * t^4 * P4 + t^5 * P5

其中 t 是参数,取值范围是 [0, 1],P0 是起始点,P1、P2、P3 和 P4 是控制点,P5 是结束点。B(t) 表示曲线上 t 时刻的点的坐标。
五次贝塞尔曲线的推导过程可以通过递归的思想来进行,即使用更低次的贝塞尔曲线来构造更高次的曲线。具体来说,我们可以使用四次贝塞尔曲线来构造五次贝塞尔曲线。
假设我们有五个四次贝塞尔曲线,它们的控制点分别是:

  1. P0, P1, P2, P3, P4
  2. P1, P2, P3, P4, P5
  3. P2, P3, P4, P5, Q (一个临时点)
  4. P3, P4, P5, Q, Q
  5. P4, P5, Q, Q, Q
    我们可以看到,这五个四次贝塞尔曲线共享了 P3 和 P4 这两个控制点。我们可以在这五个四次贝塞尔曲线之间进行插值,以得到最终的五次贝塞尔曲线。
    设 t 为参数,我们可以定义四个中间点 R0、R1、R2 和 R3,它们分别是在 t = 0、t = 1/4、t = 1/2 和 t = 3/4 时,上述五个四次贝塞尔曲线上的点。然后,我们在 R0 和 R1 之间、R1 和 R2 之间、R2 和 R3 之间、R3 和 Q 之间分别构造三次贝塞尔曲线。

最后,我们在这些三次贝塞尔曲线之间进行插值,得到最终的五次贝塞尔曲线上的点 B(t)。通过这种方式,我们可以得到五次贝塞尔曲线的公式:

B(t) = (1 - t)^5 * P0 + 5 * (1 - t)^4 * t * P1 + 10 * (1 - t)^3 * t^2 * P2 + 10 * (1 - t)^2 * t^3 * P3 + 5 * (1 - t) * t^4 * P4 + t^5 * P5

这就是五次贝塞尔曲线的推导过程。通过这种方式,我们可以看到五次贝塞尔曲线是如何从四次贝塞尔曲线的基础上构造出来的,同时也揭示了控制点 P1、P2、P3 和 P4 如何影响曲线的形状。五次贝塞尔曲线在计算机图形学中非常有用,因为它提供了一种灵活的方式来绘制非常复杂的曲线形状。

#include <SDL.h>
#include <stdio.h>
#include <math.h>
#include <stdbool.h>#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600// 定义一个结构体来表示一个点
typedef struct {float x;float y;
} Point;// 计算五次贝塞尔曲线上的点
Point calculateBezierPoint(Point p0, Point p1, Point p2, Point p3, Point p4, Point p5, float t) {Point p;float u = 1 - t;float tt = t * t;float uu = u * u;float uuu = uu * u;float uuuu = uuu * u;float ttt = tt * t;float tttt = ttt * t;p.x = uuuu * u * u * p0.x + 5 * uuuu * u * t * t * p1.x + 10 * uuu * u * tt * t * p2.x + 10 * uu * uu * ttt * p3.x + 5 * uu * u * tttt * p4.x + tttt * t * t * p5.x;p.y = uuuu * u * u * p0.y + 5 * uuuu * u * t * t * p1.y + 10 * uuu * u * tt * t * p2.y + 10 * uu * uu * ttt * p3.y + 5 * uu * u * tttt * p4.y + tttt * t * t * p5.y;return p;
}int main(int argc, char* args[]) {SDL_Window* window = NULL;SDL_Renderer* renderer = NULL;if (SDL_Init(SDL_INIT_VIDEO) < 0) {printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());return 1;}window = SDL_CreateWindow("Bezier Curve Visualization", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);if (window == NULL) {printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());return 1;}renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);if (renderer == NULL) {printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());return 1;}SDL_Event e;bool quit = false;while (!quit) {while (SDL_PollEvent(&e) != 0) {if (e.type == SDL_QUIT) {quit = true;}}SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);SDL_RenderClear(renderer);// 定义六个控制点Point p0 = {100.0, 500.0};Point p1 = {200.0, 400.0};Point p2 = {300.0, 300.0};Point p3 = {400.0, 200.0};Point p4 = {500.0, 100.0};Point p5 = {600.0, 50.0};// 绘制控制点SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);SDL_RenderDrawPoint(renderer, (int)p0.x, (int)p0.y);SDL_RenderDrawPoint(renderer, (int)p1.x, (int)p1.y);SDL_RenderDrawPoint(renderer, (int)p2.x, (int)p2.y);SDL_RenderDrawPoint(renderer, (int)p3.x, (int)p3.y);SDL_RenderDrawPoint(renderer, (int)p4.x, (int)p4.y);SDL_RenderDrawPoint(renderer, (int)p5.x, (int)p5.y);// 绘制五次贝塞尔曲线SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);Point prev = p0;for (float t = 0.01; t <= 1.0; t += 0.01) {Point current = calculateBezierPoint(p0, p1, p2, p3, p4, p5, t);SDL_RenderDrawLine(renderer, (int)prev.x, (int)prev.y, (int)current.x, (int)current.y);prev = current;}SDL_RenderPresent(renderer);}SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return 0;
}

在这个程序中,calculateBezierPoint函数接受一个包含六个点的数组和一个参数t,然后使用五次贝塞尔曲线的公式来计算曲线上对应于t的点。main函数定义了六个控制点,并使用一个循环来计算并打印曲线上的一系列点。

这篇关于贝塞尔曲线二(一次到五次)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/811982

相关文章

PR曲线——一个更敏感的性能评估工具

在不均衡数据集的情况下,精确率-召回率(Precision-Recall, PR)曲线是一种非常有用的工具,因为它提供了比传统的ROC曲线更准确的性能评估。以下是PR曲线在不均衡数据情况下的一些作用: 关注少数类:在不均衡数据集中,少数类的样本数量远少于多数类。PR曲线通过关注少数类(通常是正类)的性能来弥补这一点,因为它直接评估模型在识别正类方面的能力。 精确率与召回率的平衡:精确率(Pr

(function() {})();只执行一次

测试例子: var xx = (function() {     (function() { alert(9) })(); alert(10)     return "yyyy";  })(); 调用: alert(xx); 在调用的时候,你会发现只弹出"yyyy"信息,并不见弹出"10"的信息!这也就是说,这个匿名函数只在立即调用的时候执行一次,这时它已经赋予了给xx变量,也就是只是

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位 一、背景二、定位问题三、解决方法 一、背景 flume系列之:定位flume没有关闭某个时间点生成的tmp文件的原因,并制定解决方案在博主上面这篇文章的基础上,在机器内存、cpu资源、flume agent资源都足够的情况下,flume agent又出现了tmp文件无法关闭的情况 二、

jmeter之仅一次控制器

仅一次控制器作用: 不管线程组设置多少次循环,它下面的组件都只会执行一次 Tips:很多情况下需要登录才能访问其他接口,比如:商品列表、添加商品到购物车、购物车列表等,在多场景下,登录只需要1次,我们期望的是重复执行登陆后面的接口来做压测,这就和事务相关,例如 事务1: 登录—>添加购物车 事务2: 登录—>购物车列表 事务3: 登录—>商品列表—>添加购物车 … 一、仅一次控制器案例 在

一次生产环境大量CLOSE_WAIT导致服务无法访问的定位过程

1.症状 生产环境的一个服务突然无法访问,服务的交互过程如下所示: 所有的请求都是通过网关进入,之后分发到后端服务。 现在的情况是用户服务无法访问商旅服务,网关有大量java.net.SocketTimeoutException: Read timed out报错日志,商旅服务也不断有日志打印,大多是回调和定时任务日志,所以故障点在网关和商旅服务,大概率是商旅服务无法访问导致网关超时。 后

关于一次速度优化的往事

来自:hfghfghfg, 时间:2003-11-13 16:32, ID:2292221你最初的代码 Button1 34540毫秒 5638毫秒  Button2 我的代码 这个不是重点,重点是这个  来自:hfghfghfg, 时间:2003-11-13 16:54, ID:22923085528毫秒 不会吧,我是赛杨1.1G  128M内存  w2000, delphi6  128M

一次关于生产环境服务无故宕机的排查过程

故事的开始 这个故事是在一年之前,当时我们的系统运行在客户的k8s环境上。然后很神奇的是每个月底我们都会服务宕机,当然我们开启了多个实例。当时的容器线条就像心跳图一样(或许有些描述的不太准确,我没有找到当时那个像心电图一样的容器资源监控图)。 第一次的排查 当时我们还是很有信心去解决这个问题的。由于每个月的月底都是业务使用的高峰时段,也就是说,从表象上来看,qps一高,容器就挂。 业务日

Matlab中BaseZoom()函数实现曲线和图片的局部放大

BaseZoom工具下载链接: 链接:https://pan.baidu.com/s/1yItVSinh6vU4ImlbZW6Deg?pwd=9dyl 提取码:9dyl 下载完之后将工具包放置合适的路径下,并在matlab中“设置路径”中添加相应的路径; 注:可以先运行如下图片中的语句,看看是否报错;如果报如下错误,说明matlab未安装“Image Processing Toolbox”工

记一次knife4j文档请求异常 SyntaxError: Unexpected token ‘<‘, ... is not valid JSON

knife4j页面报错问题定位 前几天开发新接口,开发完成后想使用knife4j测试一下接口功能,突然发现访问页面报错提示:knife4j文档请求异常,但之前运行还是正常的,想想会不会与升级依赖有关系,启动其他微服务发现文档接口访问正常,排除因依赖版本升级导致在线API文档无法使用情况,还是和本服务新增接口有关系。 定位问题 首先f12打开调试台,重新刷新页面,看到console有报错提示

记一次项目启动报错问题

今天遇到了一个问题,困扰了我几个小时,虽然最后是一个小问题导致的。记录下,也算一个解决问题的方法。   前提:调用webservice时引用 <dependency><groupId>org.codehaus.xfire</groupId><artifactId>xfire-all</artifactId><version>1.2.6</version></dependency>