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

使用Python实现图形学曲线和曲面的NURBS算法

目录

    • 使用Python实现图形学曲线和曲面的NURBS算法
      • 引言
      • NURBS曲线的数学原理
        • 1. NURBS曲线定义
        • 2. 权重的作用
      • NURBS曲线的Python实现
        • 1. 类结构设计
        • 2. 代码实现
        • 3. 代码详解
        • 使用示例
      • NURBS曲面的扩展
        • NURBS曲面类实现
      • 总结

使用Python实现图形学曲线和曲面的NURBS算法

引言

NURBS(Non-Uniform Rational B-Splines,非均匀有理B样条)是一种广泛应用于计算机图形学、CAD、动画设计和3D建模的数学表示方法。它是B样条(B-spline)的推广,能够表示直线、圆弧、椭圆以及更复杂的自由曲线和曲面。NURBS通过增加权重,赋予了控制点不同的影响力,从而能够精确表示圆形等几何形状。

本文将介绍NURBS曲线和曲面的基本原理,并使用Python面向对象的思想实现NURBS算法。

NURBS曲线的数学原理

1. NURBS曲线定义

NURBS曲线由控制点、权重和节点向量定义。给定 n + 1 n+1 n+1 个控制点 P 0 , P 1 , . . . , P n P_0, P_1, ..., P_n P0,P1,...,Pn,每个控制点对应一个权重 w 0 , w 1 , . . . , w n w_0, w_1, ..., w_n w0,w1,...,wn,NURBS曲线在参数 t t t 处的点 C ( t ) C(t) C(t) 的表达式为:

C ( t ) = ∑ i = 0 n N i , p ( t ) w i P i ∑ i = 0 n N i , p ( t ) w i C(t) = \frac{\sum_{i=0}^{n} N_{i,p}(t) w_i P_i}{\sum_{i=0}^{n} N_{i,p}(t) w_i} C(t)=i=0nNi,p(t)wii=0nNi,p(t)wiPi

其中:

  • N i , p ( t ) N_{i,p}(t) Ni,p(t) 是B样条基函数,和B样条曲线的定义一致。
  • w i w_i wi 是控制点的权重,控制点对曲线的影响力大小。
  • 节点向量 t t t 决定参数空间的分布。
2. 权重的作用

权重 w i w_i wi 决定了每个控制点对曲线的影响力。若所有权重相等,则NURBS曲线退化为普通的B样条曲线;而如果控制点的某些权重远大于其他权重,则这些控制点对曲线形状的影响力会更大。

NURBS曲线的Python实现

1. 类结构设计

我们将设计以下几个类:

  • Point2D:表示二维平面上的点。
  • NURBSCurve:用于计算和绘制NURBS曲线的类。
2. 代码实现
import numpy as np

# 定义二维点类
class Point2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"({self.x}, {self.y})"

# 定义NURBS曲线类
class NURBSCurve:
    def __init__(self, control_points, weights, degree, knot_vector=None):
        """
        初始化NURBS曲线
        :param control_points: 控制点的列表,每个控制点是一个 Point2D 对象
        :param weights: 控制点的权重列表
        :param degree: NURBS的阶数(degree)
        :param knot_vector: 节点向量,若为None,则使用均匀节点向量
        """
        self.control_points = control_points
        self.weights = weights
        self.degree = degree
        self.num_control_points = len(control_points)
        
        # 生成均匀节点向量
        if knot_vector is None:
            self.knot_vector = self._generate_uniform_knot_vector()
        else:
            self.knot_vector = knot_vector

    def _generate_uniform_knot_vector(self):
        """
        生成均匀的节点向量
        :return: 均匀节点向量
        """
        n = self.num_control_points - 1
        p = self.degree
        return [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.0
        else:
            # 计算两个部分
            coef1 = 0.0
            if 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.0
            if 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 + coef2

    def calculate_point(self, t):
        """
        计算曲线在参数t处的点
        :param t: 参数值 t, 范围 [0, 1]
        :return: 返回曲线在 t 处的 Point2D 点
        """
        numerator_x = 0.0
        numerator_y = 0.0
        denominator = 0.0
        for i in range(self.num_control_points):
            b = self._basis_function(i, self.degree, t)
            numerator_x += b * self.weights[i] * self.control_points[i].x
            numerator_y += b * self.weights[i] * self.control_points[i].y
            denominator += b * self.weights[i]
        return Point2D(numerator_x / denominator, numerator_y / denominator)

    def generate_curve_points(self, num_points=100):
        """
        生成NURBS曲线上的点
        :param num_points: 生成的曲线上点的数量
        :return: 返回点列表,表示NURBS曲线
        """
        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)]
    
    # 定义权重
    weights = [1, 0.5, 0.5, 1]
    
    # 创建NURBS曲线对象,阶数为3(三次NURBS)
    nurbs_curve = NURBSCurve(control_points, weights, degree=3)
    
    # 生成并输出曲线上的点
    curve_points = nurbs_curve.generate_curve_points()
    print("NURBS曲线上的点:")
    for point in curve_points:
        print(point)
3. 代码详解
  • Point2D 类:表示二维平面上的一个点,包含点的 x x x y y y 坐标。

  • NURBSCurve 类:该类用于计算NURBS曲线,主要包括以下方法:

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

假设我们有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),并为其中两个控制点设置较小的权重 0.5 0.5 0.5,这将影响曲线的形状。生成的曲线在权重较大的控制点附近会更接近这些点。

NURBS曲面的扩展

NURBS曲线可以扩展为NURBS曲面。NURBS曲面是由二维控制点网格、权重矩阵以及两个方向的节点向量控制的。

NURBS曲面类实现
# 定义NURBS曲面类
class NURBSSurface:
    def __init__(self, control_points_grid, weights_grid, degree_u, degree_v, knot_vector_u=None, knot_vector_v=None):
        """
        初始化NURBS曲面
        :param control_points_grid: 控制点的二维网格,每个点是

 Point2D 对象
        :param weights_grid: 权重的二维网格
        :param degree_u: u方向的NURBS阶数
        :param degree_v: v方向的NURBS阶数
        :param knot_vector_u: u方向的节点向量
        :param knot_vector_v: v方向的节点向量
        """
        self.control_points_grid = control_points_grid
        self.weights_grid = weights_grid
        self.degree_u = degree_u
        self.degree_v = degree_v
        self.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_u
        
        if 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_v

    def _generate_uniform_knot_vector(self, num_control_points, degree):
        """
        生成均匀的节点向量
        :param num_control_points: 控制点数量
        :param degree: NURBS阶数
        :return: 均匀节点向量
        """
        return [0] * (degree + 1) + list(range(1, num_control_points - degree)) + [num_control_points - degree] * (degree + 1)

    def calculate_point(self, u, v):
        """
        计算NURBS曲面在参数 (u, v) 处的点
        :param u: u方向参数值
        :param v: v方向参数值
        :return: 返回曲面在 (u, v) 处的 Point2D 点
        """
        numerator_x = 0.0
        numerator_y = 0.0
        denominator = 0.0
        for i in range(self.num_control_points_u):
            for j in range(self.num_control_points_v):
                b_u = NURBSCurve._basis_function(self, i, self.degree_u, u)
                b_v = NURBSCurve._basis_function(self, j, self.degree_v, v)
                numerator_x += b_u * b_v * self.weights_grid[i][j] * self.control_points_grid[i][j].x
                numerator_y += b_u * b_v * self.weights_grid[i][j] * self.control_points_grid[i][j].y
                denominator += b_u * b_v * self.weights_grid[i][j]
        return Point2D(numerator_x / denominator, numerator_y / denominator)

    def generate_surface_points(self, num_points_u=10, num_points_v=10):
        """
        生成NURBS曲面上的点
        :param num_points_u: u方向点的数量
        :param num_points_v: v方向点的数量
        :return: 返回二维点列表,表示NURBS曲面
        """
        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

总结

NURBS通过引入权重使得在精确描述几何图形(如圆和椭圆)时更加灵活。本文通过面向对象的思想,详细介绍了NURBS曲线和曲面的实现原理,并给出了Python的具体实现。


http://www.kler.cn/news/317362.html

相关文章:

  • ChartLlama: A Multimodal LLM for Chart Understanding and Generation论文阅读
  • unity Compute Shaders 使程序在GPU中运行
  • LeetCode54. 螺旋矩阵(2024秋季每日一题 21)
  • 计算机毕业设计Hadoop+PySpark深圳共享单车预测系统 PyHive 共享单车数据分析可视化大屏 共享单车爬虫 共享单车数据仓库 机器学习 深度学习
  • 工博会蓝卓逛展攻略
  • C#测试调用Ghostscript.NET浏览PDF文件
  • <刷题笔记> 二叉搜索树与双向链表注意事项
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(上)
  • 流域碳中和技术
  • 使用Docker一键部署Blossom笔记软件
  • 【C#生态园】一文详解:NHibernate、Entity Framework Core、Dapper 等 .NET ORM 框架优劣对比
  • M9410A VXT PXI 矢量收发信机,300/600/1200MHz带宽
  • 防火墙详解(三)华为防火墙基础安全策略配置(命令行配置)
  • 11. DPO 微调示例:根据人类偏好优化LLM大语言模型
  • 【电商搜索】现代工业级电商搜索技术-Ha3搜索引擎平台简介
  • 应用层-网络协议
  • Java面试篇基础部分- Java中的阻塞队列
  • 解决selenium爬虫被浏览器检测问题
  • 5. 条件 Conditionals
  • 56 mysql 用户权限相关的实现
  • Spring高手之路24——事务类型及传播行为实战指南
  • DHCP中继工作原理
  • 算法【Dijkstra算法及分层图最短路】
  • WPF实现关系图
  • Vue开发前端图片上传给java后端
  • MMD模型一键完美导入UE5-VRM4U插件方案(一)
  • 为什么三星、OPPO、红米都在用它?联发科12nm级射频芯片的深度剖析
  • Fyne ( go跨平台GUI )中文文档-入门(一)
  • Adobe预览今年晚些时候推出的AI视频工具
  • RAG技术全面解析:Langchain4j如何实现智能问答的跨越式进化?