Bezier曲线

news2024/11/24 23:51:43

1. 实验要求

2. Bezier曲线的原理 以及 公式推导

参考贝塞尔曲线(Bezier Curve)原理及公式推导_bezier曲线-CSDN博客

Bezier曲线的一些特性:

使用n个控制点\left \{ P_{1},P_{2},P_{3}......P_{n} \right \}来控制曲线形状

曲线通过起始点P_{1}和终止点P_{n},接近但不通过中间点 P_{2}-P_{n-1}

2.1 直观理解

Step 1. 在二维平面内选三个不同的点并依次用线段连接

Step 2. 在线段AB 和BC 上找到 D、E 两点,使得 \frac{AD}{DB}=\frac{BE}{EC}

Step 3. 连接DE ,并在 DE 上找到 F 点,使其满足 \frac{DF}{FE}=\frac{AD}{DB}=\frac{BE}{EC}    抛物线的三切定理

Step 4. 找出符合上述条件的所有点

2.2 bezier曲线公式

一次贝塞尔曲线:B(t) = (1-t)P_{0} + tP_{1} ,t\epsilon [0,1]

二次贝塞尔曲线:B(t) = (1-t)^{2} P_{0} + 2t(1-t) P_{1} + t^{2} P_{2}, t\epsilon [0,1]

三次贝塞尔曲线:B(t) = (1-t)^{3} P_{0} + 3t(1-t)^{2} P_{1} + 3t^{2}(1-t) P_{2}+t^{3}P_{3}, t\epsilon [0,1]

3. 简单的三次贝塞尔曲线的绘制

使用PyOpenGL(环境的配置可以查看PyOpenGL环境配置教程-CSDN博客

from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np

# 控制点
control_points = [(-0.5, -0.5), (-0.6, 0.25), (0.25, 0.25), (0.75, -0.5)]


# 计算Bezier曲线上的点
def bezier_curve(control_points, t):
    n = len(control_points) - 1
    result = [0, 0]
    for i in range(n + 1):
        result[0] += control_points[i][0] * binomial_coefficient(n, i) * ((1 - t) ** (n - i)) * (t ** i)
        result[1] += control_points[i][1] * binomial_coefficient(n, i) * ((1 - t) ** (n - i)) * (t ** i)
    return result


# 计算二项式系数
def binomial_coefficient(n, k):
    result = 1
    for i in range(1, k + 1):
        result *= (n - i + 1) / i
    return result


# 绘制Bezier曲线
def draw_bezier_curve():
    glBegin(GL_LINE_STRIP)
    for t in np.arange(0, 1.01, 0.01):
        point = bezier_curve(control_points, t)
        glVertex2fv(point)
    glEnd()

    # 绘制控制点
    glColor3f(1.0, 0.0, 0.0)  # 设置控制点颜色为红色
    glPointSize(5.0)  # 设置控制点大小
    glBegin(GL_POINTS)
    for point in control_points:
        glVertex2fv(point)
    glEnd()

    # 将相邻的控制点连线
    glColor3f(0.0, 1.0, 0.0)  # 设置连线颜色为绿色
    glBegin(GL_LINES)
    for i in range(len(control_points) - 1):
        glVertex2fv(control_points[i])
        glVertex2fv(control_points[i + 1])
    glEnd()


def display():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)
    draw_bezier_curve()
    glFlush()


def main():
    glutInit()
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(400, 400)
    glutCreateWindow(b"Bezier Curve")

    glClearColor(0.0, 0.0, 0.0, 0.0)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)
    glMatrixMode(GL_MODELVIEW)

    glutDisplayFunc(display)

    glutMainLoop()


if __name__ == "__main__":
    main()

结果

修改控制点

control_points = [(-0.5, -0.5), (0, 0.5), (0.25, -0.25), (0.5, 0.25), (0.75, 0),(0.6,-0.1)]

得到5阶贝塞尔曲线

 

 4.增加交互功能

4.1 实现鼠标可以拖动控制点

添加了两个函数,鼠标的控制

from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np

# 控制点
control_points = [(-0.5, -0.5), (0, 0.5), (0.25, -0.25), (0.5, 0.25), (0.75, 0),(0.6,-0.1)]

# 选中的控制点索引
selected_point_index = -1

# 计算Bezier曲线上的点
def bezier_curve(control_points, t):
    n = len(control_points) - 1
    result = [0, 0]
    for i in range(n + 1):
        result[0] += control_points[i][0] * binomial_coefficient(n, i) * ((1 - t) ** (n - i)) * (t ** i)
        result[1] += control_points[i][1] * binomial_coefficient(n, i) * ((1 - t) ** (n - i)) * (t ** i)
    return result

# 计算二项式系数
def binomial_coefficient(n, k):
    result = 1
    for i in range(1, k + 1):
        result *= (n - i + 1) / i
    return result

# 鼠标点击事件处理函数
def mouse(button, state, x, y):
    global selected_point_index
    if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        # 将鼠标点击位置的窗口坐标转换为归一化坐标
        x_normalized = 2 * (x / glutGet(GLUT_WINDOW_WIDTH)) - 1
        y_normalized = 1 - 2 * (y / glutGet(GLUT_WINDOW_HEIGHT))

        # 寻找离鼠标点击位置最近的控制点
        min_distance = float('inf')
        for i, point in enumerate(control_points):
            distance = np.sqrt((x_normalized - point[0]) ** 2 + (y_normalized - point[1]) ** 2)
            if distance < min_distance:
                min_distance = distance
                selected_point_index = i



# 鼠标移动事件处理函数
def motion(x, y):
    global selected_point_index
    if selected_point_index != -1:
        # 将鼠标位置的窗口坐标转换为归一化坐标
        x_normalized = 2 * (x / glutGet(GLUT_WINDOW_WIDTH)) - 1
        y_normalized = 1 - 2 * (y / glutGet(GLUT_WINDOW_HEIGHT))

        # 更新选中控制点的坐标
        control_points[selected_point_index] = (x_normalized, y_normalized)

    glutPostRedisplay()  # 通知OpenGL窗口需要重新绘制


# 绘制函数
def draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)

    # 绘制Bezier曲线
    glBegin(GL_LINE_STRIP)
    for t in np.arange(0, 1.01, 0.01):
        point = bezier_curve(control_points, t)
        glVertex2fv(point)
    glEnd()

    # 绘制控制点
    glColor3f(1.0, 0.0, 0.0)
    glPointSize(5.0)
    glBegin(GL_POINTS)
    for point in control_points:
        glVertex2fv(point)
    glEnd()

    # 连接相邻的控制点
    glColor3f(0.0, 1.0, 0.0)
    glBegin(GL_LINES)
    for i in range(len(control_points) - 1):
        glVertex2fv(control_points[i])
        glVertex2fv(control_points[i + 1])
    glEnd()

    glFlush()

# 主函数
def main():
    glutInit()
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(400, 400)
    glutCreateWindow(b"Bezier Curve")

    glClearColor(0.0, 0.0, 0.0, 0.0)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)
    glMatrixMode(GL_MODELVIEW)

    glutMouseFunc(mouse)
    glutMotionFunc(motion)
    glutDisplayFunc(draw)

    glutMainLoop()

if __name__ == "__main__":
    main()

结果5阶bezier鼠标拖动演示-CSDN直播

5阶bezier鼠标拖动演示

4.2 采用鼠标添加控制点
from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np

# 控制点
control_points = []

# 是否允许添加新的控制点
allow_adding_points = True

# 是否处于控制点移动模式
is_move_mode = False

# 选中的控制点索引
selected_point_index = -1


# 计算Bezier曲线上的点
def bezier_curve(control_points, t):
    n = len(control_points) - 1
    result = [0, 0]
    for i in range(n + 1):
        result[0] += control_points[i][0] * binomial_coefficient(n, i) * ((1 - t) ** (n - i)) * (t ** i)
        result[1] += control_points[i][1] * binomial_coefficient(n, i) * ((1 - t) ** (n - i)) * (t ** i)
    return result


# 计算二项式系数
def binomial_coefficient(n, k):
    result = 1
    for i in range(1, k + 1):
        result *= (n - i + 1) / i
    return result


# 鼠标点击事件处理函数
# 鼠标点击事件处理函数
def mouse(button, state, x, y):
    global allow_adding_points, selected_point_index, is_move_mode
    if allow_adding_points and button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        # 将鼠标点击位置的窗口坐标转换为归一化坐标
        x_normalized = 2 * (x / glutGet(GLUT_WINDOW_WIDTH)) - 1
        y_normalized = 1 - 2 * (y / glutGet(GLUT_WINDOW_HEIGHT))

        # 添加新的控制点
        control_points.append((x_normalized, y_normalized))

        # 通知OpenGL窗口需要重新绘制
        glutPostRedisplay()
    elif button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        # 寻找离鼠标点击位置最近的控制点
        min_distance = float('inf')
        for i, point in enumerate(control_points):
            distance = np.sqrt((2 * x / glutGet(GLUT_WINDOW_WIDTH) - 1 - point[0]) ** 2 + (
                        1 - 2 * y / glutGet(GLUT_WINDOW_HEIGHT) - point[1]) ** 2)
            if distance < min_distance:
                min_distance = distance
                selected_point_index = i
        if min_distance < 0.05:  # 如果鼠标点击到了控制点附近,则进入控制点移动模式
            is_move_mode = True
    elif button == GLUT_LEFT_BUTTON and state == GLUT_UP:
        is_move_mode = False
        selected_point_index = -1


# 鼠标移动事件处理函数
def motion(x, y):
    global selected_point_index, is_move_mode
    if is_move_mode:
        # 将鼠标位置的窗口坐标转换为归一化坐标
        x_normalized = 2 * (x / glutGet(GLUT_WINDOW_WIDTH)) - 1
        y_normalized = 1 - 2 * (y / glutGet(GLUT_WINDOW_HEIGHT))

        # 更新选中控制点的坐标
        control_points[selected_point_index] = (x_normalized, y_normalized)

        # 通知OpenGL窗口需要重新绘制
        glutPostRedisplay()


# 键盘事件处理函数
def keyboard(key, x, y):
    global allow_adding_points
    if key == b'\r':  # 按下回车键
        allow_adding_points = False
    elif key == b'\x1b':  # 按下ESC键
        allow_adding_points = True


# 绘制函数
def draw():
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)

    # 绘制Bezier曲线
    glBegin(GL_LINE_STRIP)
    for t in np.arange(0, 1.01, 0.01):
        point = bezier_curve(control_points, t)
        glVertex2fv(point)
    glEnd()

    # 绘制控制点
    glColor3f(1.0, 0.0, 0.0)
    glPointSize(5.0)
    glBegin(GL_POINTS)
    for point in control_points:
        glVertex2fv(point)
    glEnd()

    # 连接相邻的控制点
    glColor3f(0.0, 1.0, 0.0)
    glBegin(GL_LINES)
    for i in range(len(control_points) - 1):
        glVertex2fv(control_points[i])
        glVertex2fv(control_points[i + 1])
    glEnd()

    glFlush()


# 主函数
def main():
    glutInit()
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
    glutInitWindowSize(400, 400)
    glutCreateWindow(b"Bezier Curve")

    glClearColor(0.0, 0.0, 0.0, 0.0)  # 将窗体的背景色设置为黑色

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)
    glMatrixMode(GL_MODELVIEW)

    glutMouseFunc(mouse)
    glutMotionFunc(motion)
    glutDisplayFunc(draw)
    glutKeyboardFunc(keyboard)

    glutMainLoop()


if __name__ == "__main__":
    main()

结果

bezier曲线(鼠标添加控制点+鼠标拖动控制点

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

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

相关文章

结构化绑定optional(C++基础)

结构化绑定 处理多个返回值的操作&#xff1a;C17提出 之前多返回值喜欢用struct来返回。现在会做成元组&#xff0c;下图中设置C17的版本&#xff0c;不要设置错为C语言标准。 #include<iostream> #include<string> #include<tuple> std::pair<std::st…

ubuntu下给不同串口设置别名

目录 一、绑定设备ID 1.查看设备ID 2.编写usev规则 3.重新加载usev规则 4.查看 二、绑定USB端口号 1.先插入一个串口&#xff0c;查看USB设备信息 2.查看USB转串口信息 3.编写usev规则 4.重新加载usev规则 5.查看 在Ubuntu环境下&#xff0c;有时候工控机或者arm开…

新增收货地址

目录 &#x1f9c2;1.创建controller层 &#x1f953;2.创建service层 &#x1f32d;3.注意细节 &#x1f37f;4.避免dao数据暴漏 1.创建controller层 controller不做逻辑操作&#xff0c;只接受前端的数据 1.添加Api设置swagger模块名称2.RestController以json形式返回…

CAJViewer8.1下载地址及安装教程

CAJViewer是中国学术期刊&#xff08;CAJ&#xff09;全文数据库的专用阅读软件。CAJViewer是中国知识资源总库&#xff08;CNKI&#xff09;开发的一款软件&#xff0c;旨在方便用户在线阅读和下载CAJ数据库中的学术论文、期刊和会议论文等文献资源。 CAJViewer具有直观的界面…

2000-2021年各省技术市场发展水平数据(原始数据+计算结果)

2000-2021年各省技术市场发展水平数据&#xff08;原始数据计算结果&#xff09; 1、时间&#xff1a;2000-2021年 2、来源&#xff1a;国家统计局、统计年鉴 3、范围&#xff1a;30省 4、指标&#xff1a;技术市场成交额、国内生产总值、技术市场发展水平 5、计算说明“技…

java字符串(一)-- 字符串API,StringBuffer 和 StringBuilder,Object

String字符串相关的类 String的特性 String类&#xff1a;代表字符串。Java 程序中的所有字符串字面值&#xff08;如"abc" &#xff09;都作为此类的实例实现。String类是引用数据类型。 在 Java 8 中&#xff0c;String 内部使用 char 数组存储数据。 public fi…

C++的入门学习

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一、C关键字(C98) 二、命名空间 2.1 引入 ​编辑2.2 命名空间定义 2.3 命名空间的使用 三. C输入&输出 四.缺省参数 4.1 缺省参数概念 4.2 缺省参数分类 1.全缺省参数 2…

MCGS学习——水位控制

要求 插入一个水罐&#xff0c;液位最大值为37插入一个滑动输入器&#xff0c;用来调节水罐水位&#xff0c;滑动输入器最大调节为液位最大值&#xff0c;并能清楚的显示出液位情况用仪表显示水位变化情况&#xff0c;仪表最大显示设置直观清楚方便读数&#xff0c;主划线为小…

基于spark的大数据分析预测地震受灾情况的系统设计

基于spark的大数据分析预测地震受灾情况的系统设计 在本篇博客中,我们将介绍如何使用Apache Spark框架进行地震受灾情况的预测。我们将结合数据分析、特征工程、模型训练和评估等步骤,最终建立一个预测模型来预测地震造成的破坏程度,同时使用可视化大屏的方式展示数据的分布…

提升 RAG 效果的实践

提升 RAG 效果的实践 0. 引言1. 测试数据2. cohere/embed-multilingual-v3.0 的几组测试结果2-1. 第1组测试2-2. 第2组测试 3. BAAI/bge-m3 的几组测试结果3-1. 第1组测试 0. 引言 AI 大语言模型的主要应用方式之一就是 RAG&#xff0c;接下来计划陆续分享工作中提升 RAG 效果…

vue3封装Element表格

配置表头配置多选配置序号自定义操作列按钮 封装表格 Table.vue <template><el-table:data"tableData"width"100%":maxHeight"maxHeight"v-bind"$attrs"selection-change"handleSelectChange"row-click"hand…

考研数学|听完一遍汤家凤基础,1800都没思路,怎么办?

看了我这篇回答&#xff0c;保证你可以顺利的做1800题&#xff01; 如果你听了汤家凤老师的课&#xff0c;但是做题没思路&#xff0c;请不要担心&#xff0c;也不要急着换老师&#xff0c;你很有可能是方法错了。 请你反思一下&#xff1a; 1、你是不是听完课立刻就去做题。…

linux系统基础命令

1、Linux中文件的权限包括哪些&#xff1f;某个文件的权限列为644代表该文件属主、属组和其它用户分别有什么权限&#xff1f; 1&#xff09;Linux中文件的权限包括哪些&#xff1f; 在Linux系统中&#xff0c;文件的权限包括读取&#xff08;r&#xff09;、写入&#xff08;w…

ARP类型

地址解析协议ARP即可实现将IP地址解析为MAC地址 动态ARP 动态ARP表项由ARP协议通过ARP报文自动生成和维护&#xff0c;可以被老化&#xff0c;可以被新的ARP报文更新&#xff0c;也可以被静态ARP表项覆盖。 动态ARP适用于拓扑结构复杂、通信实时性要求高的网络。 静态ARP …

C刊级 | Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测

C刊级 | Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 C刊级 | Matlab实现DBO-BiTCN-BiGRU-Attention蜣螂算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测效果一览基本介绍模型描述程序…

(React组件基础)前端八股文Day6

一 类组件与函数组件有什么异同 在React中&#xff0c;类组件和函数组件是创建组件的两种主要方式。随着React的发展&#xff0c;尤其是自Hooks在React 16.8中引入以来&#xff0c;函数组件的功能变得更加强大&#xff0c;使得它们能够更加方便地与类组件相竞争。下面是类组件…

雷卯有1.8V的ESD供您选择

一&#xff0e;雷卯有1.8V的ESD供您选择&#xff0c;如下是型号&#xff0c;体积小。 二. 为什么要用低压1.8V 做静电保护呢 省电&#xff0c;省电&#xff01; 1.8V的电压&#xff0c;内阻也小的话&#xff0c;那就是非常省电的电路。现在很多产品号称10年不用换电池。电池技…

基于Springboot旅游网站管理系统设计和实现

基于Springboot旅游网站管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系…

内网渗透-(黄金票据和白银票据)详解(一)

目录 一、Kerberos协议 二、下面我们来具体分析Kerberos认证流程的每个步骤&#xff1a; 1、KRB_AS-REQ请求包分析 PA-ENC-TIMESTAMP PA_PAC_REQUEST 2、 KRB_AS_REP回复包分析&#xff1a; TGT认购权证 Logon Session Key ticket 3、然后继续来讲相关的TGS的认证过程…

在react项目用echarts绘制中国地图

文章目录 一、引入echarts二、下载地图json数据三、编写react组件四、组件使用 一、引入echarts 安装&#xff1a;npm i echarts --save 二、下载地图json数据 由于echarts内部不再支持地图数据&#xff0c;所以要绘制地图需要自己去下载数据。建议使用阿里云的。 地址&…