求B样条曲线各个点坐标及C++实现

功能:根据参数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 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;
}
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: B样条曲线是一种在计算机图形学和计算机辅助设计中常用的曲线表示方法,其可以由一些控制通过插值或逼近的方式生成。 反控制即给定一个B样条曲线c,我们需要推导出生成这条曲线所使用的控制。 在B样条曲线中,每个控制的位置决定了曲线的形状。假设我们有n个控制曲线的阶数为k。 首先,我们需要确定控制的个数n以及曲线的阶数k。控制的个数至少为k+1,而曲线的阶数大于等于2。 然后,从曲线c上取一系列参数值(t1, t2, ..., tn),这些参数值决定了曲线上的一些。根据B样条曲线的定义,我们可以使用这些参数值和其对应的坐标,建立一个线性方程组。 对于每个参数值ti,根据曲线c的定义,我们可以得到一个方程: P(ti) = C[0]*N[0,k](ti) + C[1]*N[1,k](ti) + ... + C[n-1]*N[n-1,k](ti) 其中,P(ti)为曲线上的坐标,C[i]为控制坐标,N[i,k](ti)为B样条基函数。 我们可以利用这个方程组解C[i],进而得到曲线c的控制。 因此,反控制绘制曲线c的过程就是通过已知的曲线和参数值,建立线性方程组,然后解控制坐标。 注意,反控制的准确性取决于参数值的选择和曲线的阶数。参数值越分散且曲线阶数越高,反得到的控制越精确,能更好地重现原始曲线的形状。 ### 回答2: B样条控制绘制曲线C是一种数学计算方法。B样条曲线是由数个控制确定的光滑曲线,通过这些控制可以绘制出平滑连续的曲线C。 反控制是指已知曲线C的形状,通过计算得到曲线上的控制坐标。这个过程可以通过数学方法中的插值或者拟合方法来实现。 在B样条曲线中,控制的位置决定了曲线的形状。当我们知道曲线C的形状时,我们可以通过数学计算方法,推导出曲线上的控制坐标。 具体的反控制方法有很多,其中一个常用的方法是最小二乘法。最小二乘法通过寻找最优解,使得曲线C的形状与控制的位置最符合,最小化它们之间的误差。 通过反控制的计算,我们可以得到曲线上的一系列控制坐标,这些控制的位置可以用于绘制出曲线C。绘制曲线C时,我们可以通过连接相邻的控制来形成曲线段,再过渡到下一个曲线段,最终绘制出整个曲线C。 B样条控制绘制曲线C是一种非常有用的技术,可以满足我们对曲线形状的要。通过这种方法,我们可以灵活地控制曲线的形状,并且能够很好地适应各种复杂曲线的需
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值