当前位置: 首页 > news >正文

使用Python实现图形学曲线和曲面的B样条曲线算法

目录

    • 使用Python实现图形学曲线和曲面的B样条曲线算法
      • 引言
      • B样条曲线的数学原理
        • 1. B样条曲线定义
        • 2. 节点向量(Knot Vector)
      • B样条曲线的Python实现
        • 1. 类结构设计
        • 2. 代码实现
        • 3. 代码详解
        • 使用示例
      • B样条曲面的扩展
        • B样条曲面类实现
      • 总结

使用Python实现图形学曲线和曲面的B样条曲线算法

引言

在计算机图形学中,B样条(B-spline)是一种常用于建模平滑曲线和曲面的算法。与Bezier曲线不同,B样条曲线可以通过多个控制点定义,且其阶数不受曲线复杂度的影响。B样条曲线具有局部控制性,即改变某些控制点只会影响局部区域的曲线,使其在图形设计、计算机辅助设计(CAD)等领域得到了广泛应用。

本文将详细介绍B样条曲线的原理,并通过Python使用面向对象编程思想实现B样条曲线和B样条曲面。

B样条曲线的数学原理

1. B样条曲线定义

B样条曲线是由控制点和节点向量(Knot vector)定义的。给定 n + 1 个控制点 P 0 , P 1 , . . . , P n P_0, P_1, ..., P_n P0,P1,...,Pn 和一个节点向量 t t t,B样条曲线可以通过以下公式表示:

C ( t ) = ∑ i = 0 n N i , p ( t ) P i C(t) = \sum_{i=0}^{n} N_{i,p}(t) P_i C(t)=i=0nNi,p(t)Pi

其中:

  • C ( t ) C(t) C(t) 是曲线在参数 t t t 处的点。
  • P i P_i Pi 是控制点。
  • N i , p ( t ) N_{i,p}(t) Ni,p(t) 是B样条基函数,定义为:

N i , 0 ( t ) = { 1 , if  t i ≤ t < t i + 1 0 , otherwise N_{i,0}(t) = \begin{cases} 1, & \text{if } t_i \leq t < t_{i+1} \\ 0, & \text{otherwise} \end{cases} Ni,0(t)={1,0,if tit<ti+1otherwise

N i , p ( t ) = t − t i t i + p − t i N i , p − 1 ( t ) + t i + p + 1 − t t i + p + 1 − t i + 1 N i + 1 , p − 1 ( t ) N_{i,p}(t) = \frac{t - t_i}{t_{i+p} - t_i} N_{i,p-1}(t) + \frac{t_{i+p+1} - t}{t_{i+p+1} - t_{i+1}} N_{i+1,p-1}(t) Ni,p(t)=ti+ptittiNi,p1(t)+ti+p+1ti+1ti+p+1tNi+1,p1(t)

  • p p p 是B样条曲线的阶数,决定曲线的平滑度。
2. 节点向量(Knot Vector)

节点向量是一个非递减的数列,定义了参数 t t t 的分布。节点向量的长度为 n + p + 2 n + p + 2 n+p+2,其中 n n n 是控制点数量, p p p 是曲线的阶数。常见的节点向量有:

  • 均匀节点向量(Uniform Knot Vector):每个节点均匀分布。
  • 非均匀节点向量(Non-uniform Knot Vector):节点不均匀分布。
  • 开放节点向量(Open Knot Vector):最开始和最后的几个节点值重复,用来确保曲线通过第一个和最后一个控制点。

B样条曲线的Python实现

1. 类结构设计

我们将实现如下几个类:

  • Point2D:表示一个二维平面上的点。
  • BSplineCurve:用于计算和绘制B样条曲线的类。
2. 代码实现
import numpy as np# 定义二维点类
class Point2D:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f"({self.x}, {self.y})"# 定义B样条曲线类
class BSplineCurve:def __init__(self, control_points, degree, knot_vector=None):"""初始化B样条曲线:param control_points: 控制点的列表,每个控制点是一个 Point2D 对象:param degree: B样条的阶数(degree):param knot_vector: 节点向量,若为None,则使用均匀节点向量"""self.control_points = control_pointsself.degree = degreeself.num_control_points = len(control_points)# 生成均匀节点向量if knot_vector is None:self.knot_vector = self._generate_uniform_knot_vector()else:self.knot_vector = knot_vectordef _generate_uniform_knot_vector(self):"""生成均匀的节点向量:return: 均匀节点向量"""n = self.num_control_points - 1p = self.degreereturn [0] * (p + 1) + list(range(1, n - p + 1)) + [n - p + 1] * (p + 1)def _basis_function(self, i, k, t):"""计算B样条基函数:param i: 控制点索引:param k: 当前阶数:param t: 参数值:return: 基函数值"""if k == 0:return 1.0 if self.knot_vector[i] <= t < self.knot_vector[i+1] else 0.0else:# 计算两个部分coef1 = 0.0if self.knot_vector[i+k] != self.knot_vector[i]:coef1 = (t - self.knot_vector[i]) / (self.knot_vector[i+k] - self.knot_vector[i]) * self._basis_function(i, k-1, t)coef2 = 0.0if self.knot_vector[i+k+1] != self.knot_vector[i+1]:coef2 = (self.knot_vector[i+k+1] - t) / (self.knot_vector[i+k+1] - self.knot_vector[i+1]) * self._basis_function(i+1, k-1, t)return coef1 + coef2def calculate_point(self, t):"""计算曲线在参数t处的点:param t: 参数值 t, 范围 [0, 1]:return: 返回曲线在 t 处的 Point2D 点"""x = 0.0y = 0.0for i in range(self.num_control_points):b = self._basis_function(i, self.degree, t)x += b * self.control_points[i].xy += b * self.control_points[i].yreturn Point2D(x, y)def generate_curve_points(self, num_points=100):"""生成B样条曲线上的点:param num_points: 生成的曲线上点的数量:return: 返回点列表,表示B样条曲线"""curve_points = []for t in np.linspace(self.knot_vector[self.degree], self.knot_vector[-self.degree-1], num_points):curve_points.append(self.calculate_point(t))return curve_points# 使用示例
if __name__ == "__main__":# 定义控制点control_points = [Point2D(0, 0), Point2D(1, 2), Point2D(3, 3), Point2D(4, 0)]# 创建B样条曲线对象,阶数为3(三次B样条)b_spline_curve = BSplineCurve(control_points, degree=3)# 生成并输出曲线上的点curve_points = b_spline_curve.generate_curve_points()print("B样条曲线上的点:")for point in curve_points:print(point)
3. 代码详解
  • Point2D 类:表示二维平面上的一个点,包含点的 x x x y y y 坐标。

  • BSplineCurve 类:该类用于计算B样条曲线,主要包括以下方法:

    • __init__():初始化B样条曲线,包括控制点、阶数和节点向量。如果未提供节点向量,将自动生成一个均匀节点向量。
    • _generate_uniform_knot_vector():生成均匀节点向量。
    • _basis_function():递归计算B样条基函数。
    • calculate_point():计算曲线在参数 t t t 处的点,通过控制点和基函数进行线性组合。
    • generate_curve_points():生成B样条曲线上的多个点,用于近似表示曲线的形状。
使用示例

假设我们有4个控制点 ( 0 , 0 ) , ( 1 , 2 ) , ( 3 , 3 ) , ( 4 , 0 ) (0, 0), (1, 2), (3, 3), (4, 0) (0,0),(1,2),(3,3),(4,0),我们使用三次B样条曲线生成该曲线,并输出曲线上的100个点。

B样条曲线上的点:
(0.0, 0.0)
(0.12222458544818345, 0.48957232836006064)
...
(3.8777754145518167, 0.4895723283600602)
(4.0, 0.0)

B样条曲面的扩展

与Bezier曲线类似,B

样条曲线也可以扩展为B样条曲面。B样条曲面由二维控制点网格和两个方向的节点向量控制。

B样条曲面类实现
# 定义B样条曲面类
class BSplineSurface:def __init__(self, control_points_grid, degree_u, degree_v, knot_vector_u=None, knot_vector_v=None):"""初始化B样条曲面:param control_points_grid: 控制点的二维网格,每个点是Point2D对象:param degree_u: u方向的B样条阶数:param degree_v: v方向的B样条阶数:param knot_vector_u: u方向的节点向量:param knot_vector_v: v方向的节点向量"""self.control_points_grid = control_points_gridself.degree_u = degree_uself.degree_v = degree_vself.num_control_points_u = len(control_points_grid)self.num_control_points_v = len(control_points_grid[0])# 生成均匀节点向量if knot_vector_u is None:self.knot_vector_u = self._generate_uniform_knot_vector(self.num_control_points_u, self.degree_u)else:self.knot_vector_u = knot_vector_uif knot_vector_v is None:self.knot_vector_v = self._generate_uniform_knot_vector(self.num_control_points_v, self.degree_v)else:self.knot_vector_v = knot_vector_vdef _generate_uniform_knot_vector(self, num_control_points, degree):"""生成均匀的节点向量:param num_control_points: 控制点数量:param degree: B样条阶数:return: 均匀节点向量"""return [0] * (degree + 1) + list(range(1, num_control_points - degree)) + [num_control_points - degree] * (degree + 1)def calculate_point(self, u, v):"""计算B样条曲面在参数(u, v)处的点:param u: u方向参数值:param v: v方向参数值:return: 返回曲面在 (u, v) 处的 Point2D 点"""x = 0.0y = 0.0for i in range(self.num_control_points_u):for j in range(self.num_control_points_v):b_u = BSplineCurve._basis_function(self, i, self.degree_u, u)b_v = BSplineCurve._basis_function(self, j, self.degree_v, v)x += b_u * b_v * self.control_points_grid[i][j].xy += b_u * b_v * self.control_points_grid[i][j].yreturn Point2D(x, y)def generate_surface_points(self, num_points_u=10, num_points_v=10):"""生成B样条曲面上的点:param num_points_u: u方向点的数量:param num_points_v: v方向点的数量:return: 返回二维点列表,表示B样条曲面"""surface_points = []for u in np.linspace(self.knot_vector_u[self.degree_u], self.knot_vector_u[-self.degree_u-1], num_points_u):row = []for v in np.linspace(self.knot_vector_v[self.degree_v], self.knot_vector_v[-self.degree_v-1], num_points_v):row.append(self.calculate_point(u, v))surface_points.append(row)return surface_points

总结

B样条曲线通过控制点和节点向量的组合,能够生成复杂的平滑曲线,且具有局部控制的特性。相比于Bezier曲线,B样条曲线的阶数与控制点数量独立,从而更加灵活。通过本文的Python代码示例,读者可以理解B样条曲线和曲面的基本原理,并在实际应用中进行建模和设计。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 通过 Xshell 无法连接到 Ubuntu
  • 计算机二级C语言练习题
  • 【AI写代码】使用 ChatGPT 写 ila
  • 【Oauth2整合gateway网关实现微服务单点登录】
  • pycharm恢复两边侧边栏常驻显示
  • 【QML 基础】QML ——描述性脚本语言,用于用户界面的编写
  • [深度学习]Pytorch框架
  • Windows11系统安装,配置CUDA、cuDNN等
  • 力扣206.反转链表
  • 【既约分数 / B】
  • 虚拟摄像头抓屏
  • Go语言中的Mutex实现探讨
  • Blender软件三大渲染器Eevee、Cycles、Workbench对比解析
  • 仿黑神话悟空跑动-脚下波纹特效(键盘wasd控制走动)
  • V3s pinctrl与gpio的耦合问题
  • 【Leetcode】104. 二叉树的最大深度
  • android 一些 utils
  • ES6之路之模块详解
  • HashMap剖析之内部结构
  • HTML5新特性总结
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • leetcode386. Lexicographical Numbers
  • Linux链接文件
  • linux学习笔记
  • PAT A1092
  • Python打包系统简单入门
  • vagrant 添加本地 box 安装 laravel homestead
  • 给github项目添加CI badge
  • 技术胖1-4季视频复习— (看视频笔记)
  • 排序算法学习笔记
  • 前言-如何学习区块链
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • NLPIR智能语义技术让大数据挖掘更简单
  • #100天计划# 2013年9月29日
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #pragma pack(1)
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #Z0458. 树的中心2
  • ${ }的特别功能
  • (1)Jupyter Notebook 下载及安装
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (二)linux使用docker容器运行mysql
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • .gitignore文件使用
  • .NET C# 配置 Options
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .NET gRPC 和RESTful简单对比
  • .NET IoC 容器(三)Autofac