功能:根据参数u值和k(大小为阶数值)与节点矢量,计算第i个k次B样条基数

输入参数: u—参数值;k—大小值为阶数;i—第i个k次B样条的支撑区间左端节点的下标;aNode为节点向量。

输出参数:返回函数值。

double GetBaseFunVal(double u, int i, int k, vector <double> m_aNode)

{

double Val = 0.0;

double Val1 = 0.0;

double Val2 = 0.0;

if (k==0)

{

if (u < m_aNode[i] || u > m_aNode[i+1])

return Val;

else

{

Val = 1.0;

return Val;

}

}

if (k>0)

{

if (u < m_aNode[i] || u > m_aNode[i+k+1])

{

return Val;

}

else

{

double alpha = 0.0;

double beta = 0.0;

double dTemp = 0.0;

dTemp = m_aNode[i+k] - m_aNode[i];

if (dTemp == 0.0)

{

alpha  = 0;

}

else

alpha = (u - m_aNode[i])/dTemp;

dTemp = m_aNode[i+k+1] - m_aNode[i+1];

if (dTemp == 0.0)

{

beta = 0.0;

}

else

beta = (m_aNode[i+k+1] - u)/dTemp;

Val1 = alpha * GetBaseFunVal(u, i, k-1, m_aNode);

Val2 = beta * GetBaseFunVal(u, i+1, k-1, m_aNode);

Val = Val1 + Val2;

}

}

return Val;

}

上述功能模块摘自于计算机辅助几何设计与非均匀有理B样条。已知B样条的n+1控制点坐标,以及相应的节点向量,可求得对应的曲线方程。

先计算各个控制点的基函数

各个基函数的求解可根据上述的功能模块求出。

下面是我的C++实现:曲线是二维的,三维的情况,就Z坐标做同X,Y求解方式相同即可。在求解的过程中,我自己在CAD上画了个样条曲线,然后通过GetBaseFunVal(double u, int i, int k, vector <double> m_aNode)和顶点坐标,及节点向量求各个点的坐标。随着u值的变化,计算各个X,Y,Z值。一个星期的摸爬滚打中,能输出图形,但是与原来的图形对应不上。最终找到的原因在与基函数出问题了。在书本等相关资源中,基函数成员中的k表示的是次数,在我画的样条曲线中,阶数显示为3(为什么是3?CAD的标注里,实体块中的 70 下一行,为3),所以我理所当然的写为了2,。一直有问题。我将它改为3以后,竟然奇迹般的可以用了。而且跟原来图形吻合。这个是我的相关经历,希望对你们能有用。另外,哪位热心人士可以说明下,为什么k改为阶数大小,就可以呢?

#include <iostream>
#include <fstream>
#include <afxtempl.h>

using namespace std;

struct tPoint
{
    double x;
    double y;
    double z;
};

double GetBaseFunVal(double u, int i, int k, vector <double> m_aNode)
{
    double Val = 0.0;
    double Val1 = 0.0;
    double Val2 = 0.0;
    if (k==0)
    {
        if (u < m_aNode[i] || u > m_aNode[i+1])
            return Val;
        else
        {
            Val = 1.0;
            return Val;
        }
    }
    if (k>0)
    {
        if (u < m_aNode[i] || u > m_aNode[i+k+1])
        {
            return Val;
        }
        else
        {
            double alpha = 0.0;
            double beta = 0.0;
            double dTemp = 0.0;
            dTemp = m_aNode[i+k] - m_aNode[i];
            if (dTemp == 0.0)
            {
                alpha  = 0;
            }
            else
                alpha = (u - m_aNode[i])/dTemp;
            dTemp = m_aNode[i+k+1] - m_aNode[i+1];

if (dTemp == 0.0)
            {
                beta = 0.0;
            }
            else
                beta = (m_aNode[i+k+1] - u)/dTemp;
            Val1 = alpha * GetBaseFunVal(u, i, k-1, m_aNode);
            Val2 = beta * GetBaseFunVal(u, i+1, k-1, m_aNode);
            Val = Val1 + Val2;
        }
    }

return Val;
}

int main()
{
    tPoint tData;
    vector <tPoint> vtData;

vtData.clear();
    vector <double> nodeVector;
    nodeVector.push_back(0);
    nodeVector.push_back(0);
    nodeVector.push_back(0);
    nodeVector.push_back(0);
    nodeVector.push_back(1);
    nodeVector.push_back(2);
    nodeVector.push_back(3);
    nodeVector.push_back(4);
    nodeVector.push_back(5);
    nodeVector.push_back(6);
    nodeVector.push_back(6);
    nodeVector.push_back(6);
    nodeVector.push_back(6);

//节点向量nodeVector, 控制点坐标(0,3),(200,100), (750, 200), k=2

for (double u = 0; u < 6; u=u+0.01)
    {
        // 样条的数据
        tData.x = (GetBaseFunVal(u, 0, 3, nodeVector)*(-7585) + GetBaseFunVal(u, 1, 3, nodeVector)*(-3427.5) + GetBaseFunVal(u, 2, 3, nodeVector)*46087.5
            + GetBaseFunVal(u, 3, 3, nodeVector)*9220.0 +  GetBaseFunVal(u, 4, 3, nodeVector)*(-14835.0) +  GetBaseFunVal(u, 5, 3, nodeVector)*(-2002.5) + GetBaseFunVal(u, 6, 3, nodeVector)*71975
            +  GetBaseFunVal(u, 7, 3, nodeVector)*45235 +  GetBaseFunVal(u, 8, 3, nodeVector)*83150)/*/(GetBaseFunVal(u, 0, 3, nodeVector) + GetBaseFunVal(u, 1, 3, nodeVector) + GetBaseFunVal(u, 2, 3, nodeVector)
            + GetBaseFunVal(u, 3, 3, nodeVector) +  GetBaseFunVal(u, 4, 3, nodeVector) +  GetBaseFunVal(u, 5, 3, nodeVector))*/;
         tData.y = (GetBaseFunVal(u, 0, 3, nodeVector)*(-3807.5) + GetBaseFunVal(u, 1, 3, nodeVector)*(19850.0) + GetBaseFunVal(u, 2, 3, nodeVector)*14335
             +  GetBaseFunVal(u, 3, 3, nodeVector)*(-17582.5) +  GetBaseFunVal(u, 4, 3, nodeVector)*(-5445.0) +  GetBaseFunVal(u, 5, 3, nodeVector)*(-80735.0) + GetBaseFunVal(u, 6, 3, nodeVector)*(-23817.5)
            +   GetBaseFunVal(u, 7, 3, nodeVector)*5037.5 +  GetBaseFunVal(u, 8, 3, nodeVector)*(-9360))/*/(GetBaseFunVal(u, 0, 3, nodeVector) + GetBaseFunVal(u, 1, 3, nodeVector) + GetBaseFunVal(u, 2, 3, nodeVector)
            + GetBaseFunVal(u, 3, 3, nodeVector) +  GetBaseFunVal(u, 4, 3, nodeVector) +  GetBaseFunVal(u, 5, 3, nodeVector))*/;
        tData.z = 0.0;

vtData.push_back(tData);
    }

char *file = "C:/Users/Monkey/Desktop/新建文件夹 (2)/TEST/Last.txt";
    ofstream out(file);
    if (!out)
    {
        cout << "打开文件失败!!!!" << endl;
    }

for (int n = 0; n < vtData.size(); n++)
    {
        out << vtData[n].x << "  " << vtData[n].y <<"   " << vtData[n].z << endl;
    }

out.close();

return 0;
}

B样条曲线方程和C++实现的更多相关文章

  1. B样条曲线曲面(附代码)

    1 B样条曲线 1.1 B样条曲线方程 B样条方法具有表示与设计自由型曲线曲面的强大功能,是形状数学描述的主流方法之一,另外B样条方法是目前工业产品几何定义国际标准——有理B样条方法 (NURBS)的 ...

  2. B样条基函数的定义和性质

    定义:令U={u0,u1,…,um}是一个单调不减的实数序列,即ui≤ui+1,i=0,1,…,m-1.其中,ui称为节点,U称为节点矢量,用Ni,p(u)表示第i个p次(p+1阶)B样条基函数,其定 ...

  3. B样条基函数(cubic spline basis)

    B样条基函数用作权重 reference http://blog.csdn.net/tuqu

  4. [图形学] Chp14 GLU曲面裁剪函数程序示例及样条表示遗留问题

    样条表示这章已经看完,最后的GLU曲面裁剪函数,打算按书中的示例实现一下,其中遇到了几个问题. 先介绍一下GLU曲面裁剪函数的使用方法. 1 裁剪函数是成对出现的: gluBeginTrim和gluE ...

  5. [摘抄] Bezier曲线、B样条和NURBS

    Bezier曲线.B样条和NURBS,NURBS是Non-Uniform Rational B-Splines的缩写,都是根据控制点来生成曲线的,那么他们有什么区别了?简单来说,就是: Bezier曲 ...

  6. B样条基函数的定义及系数的意义

    原文链接:http://blog.csdn.net/tuqu/article/details/5177405 贝塞尔基函数用作权重.B-样条基函数也一样:但更复杂.但是它有两条贝塞尔基函数所没有的特性 ...

  7. 样条之拉格朗日Lagrange(一元全区间)插值函数

    这是使用拉格朗日插值函数生成的样条曲线.在数值分析中,拉格朗日插值法是以法国十八世纪数学家约瑟夫·拉格朗日命名的一种多项式插值方法.许多实际问题中都用函数来表示某种内在联系或规律,而不少函数都只能通过 ...

  8. 样条之埃尔米特(Hermite)

    埃尔米特(Charles Hermite,1822—1901) 法国数学家.巴黎综合工科学校毕业.曾任法兰西学院.巴黎高等师范学校.巴黎大学教授.法兰西科学院院士.在函数论.高等代数.微分方程等方面都 ...

  9. 样条之CatmullRom

    所谓样条曲线是指给定一组控制点而得到一条曲线,曲线的大致形状由这些点予以控制,一般可分为插值样条和逼近样条两种,插值样条通常用于数字化绘图或动画的设计,逼近样条一般用来构造物体的表面.CatmullR ...

随机推荐

  1. SpringMVC 中的异常处理

    目录 1.搭建编码分析 2.编写异常类 3.编写自定义异常处理器 4.在springmvc.xml中配置异常处理器 5.编写Error.jsp.index.jsp页面 6.编写collector代码模 ...

  2. Guava中强大的排序器Ordering使用

    一 创建排序器 排序器:可以用来为构建复杂的比较器,以完成集合排序的功能: 本质上来说,Ordering 实例无非就是一个特殊的Comparator 实例. Ordering把很多基于Comparat ...

  3. PuTTYTabManager汉化版

    PuTTY Tab Manager(puttytm) V0.52 zh_CN 简体中文汉化版 功能 Putty是一款小巧好用免费的SSH客户端工具,但是不支持多标签管理,网上找了一些相关的putty多 ...

  4. 暑假第七周总结(安装MongoDB和Tomcat以及MongoDB进行编程实践)

    本周主要对MongoDB和Tomcat进行了安装,两项安装都遇到了一些问题.其中在对MongoDB安装过程中出现了什么没有秘钥安全证书的,最终找了一堆教程重复了好多遍之后安装成功,虽然在启动和关闭的时 ...

  5. openstack中的延迟删除

    glance镜像的延迟删除 在控制节点的glance-api.conf文件中设置延迟删除: # Turn on/off delayed delete delayed_delete = False # ...

  6. SpringBoot之切面AOP

    SpringBoot提供了强大AOP支持,我们前面讲解过AOP面向切面,所以这里具体AOP原理就补具体介绍: AOP切面主要是切方法,我们一般搞一些日志分析和事务操作,要用到切面,类似拦截器: @As ...

  7. WTL Picture Control显示图片

    1.在对话框上新建一个Picture Control ID为:IDC_STATIC_IMG 2.添加图片资源ID:IDB_BITMAP1(选中Bitmap点击导入,选择bmp图片资源) 实现: CWi ...

  8. Lua使用luasocket http请求例子

    local http=require("socket.http"); local request_body = [[login=user&password=123]] lo ...

  9. 调用caffe脚本将图片转换为了lmdb格式

    #!/usr/bin/env sh # Create the imagenet lmdb inputs # N.B. set the path to the imagenet train + val ...

  10. Kafka系列2:深入理解Kafka消费者

    Kafka系列2:深入理解Kafka消费者 上篇聊了Kafka概况,包含了Kafka的基本概念.设计原理,以及设计核心.本篇单独聊聊Kafka的消费者,包括如下内容: 生产者是如何生产消息 如何创建生 ...