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

C-5 B样条曲线

C-5 B样条曲线

N i , 0 ( u ) = { 1 , u i ≤ u < u i + 1 0 , o t h e r s N_{i,0}(u)=\left\{\begin{matrix} 1 , \quad u_i\le u <u_{i+1} \\0 ,\quad others \qquad \quad\end{matrix}\right. Ni,0(u)={1,uiu<ui+10,others

N i , p ( u ) = u − u i u i + p − u i ⋅ N i , p − 1 ( u ) + u i + p + 1 − u u i + p + 1 − u i + 1 ⋅ N i + 1 , p − 1 ( u ) N_{i,p}(u)=\frac{u -u_i}{u_{i+p}-u_i} \cdot N_{i,p-1}(u) +\frac{u_{i+p+1} -u}{u_{i+p+1}-u_{i+1}} \cdot N_{i+1,p-1}(u) Ni,p(u)=ui+puiuuiNi,p1(u)+ui+p+1ui+1ui+p+1uNi+1,p1(u)

C ( u ) = ∑ i = 1 n N i , p ( u ) ⋅ C o n t r o l P o i n t ( i ) C(u) = \sum ^n_{i=1} N_{i,p}(u)\cdot ControlPoint_{(i)} C(u)=i=1nNi,p(u)ControlPoint(i)

  • C就是我们要求的曲线

  • 只需要给定控制点数组和节点向量数组,我们就能根据以上公式得到一条B样条曲线。

  • n是给定控制点数组的长度,p是B样条的阶数,一般就直接设置为3了, u i u_i ui就算节点向量数组,可以从公式中发现,节点向量的长度等于 控制点数组长度+阶数+1。(从递归公式中的 u i + p + 1 u_{i+p+1} ui+p+1可以看出来)

  • 前面的参数 N i , p N_{i,p} Ni,p,只需要给定节点向量和阶数就能直接提前求出来,可以写成矩阵的形式。方便后面移动控制点求解。

  • 在Step标准中,B样条是如下定义的:

    • 
      #21=B_SPLINE_CURVE_WITH_KNOTS('',3,(#118,#119,#120,#121),.UNSPECIFIED.,
       .F.,.F.,(4,4),(0.,1.),.UNSPECIFIED.);
        //相当于输入控制点 (#118,#119,#120,#121),和节点向量(0,0,0,0,1,1,1,1)
       //有一个重复的节点,那里的连续性就会减一,具体可以见Games102,刘利刚老师的课
       //3指3阶B样条曲线,第一个F指这个曲线没有闭合,(4,4)是修饰后面的节点向量,这条曲线比较简单,一般是下面#31这样的
       //1阶B样条曲线的连续性是C1,也就是连连上,导数不连续。而3阶B样条曲线的连续性是C3
      
       #31=B_SPLINE_CURVE_WITH_KNOTS('',3,(#88,#89,#90,#91,#92,#93,#94),
       .UNSPECIFIED.,.T.,.F.,(4,1,1,1,4),(0.,0.190110440975709,0.596109450554148,
      0.871779783977488,1.),.UNSPECIFIED.);
      

局部性

  • 局部性:我们操控第i个控制点,只能控制有限的一段曲线而不是影响到这条曲线
  • 我们发现,控制点i前面的参数是 N i , p N_{i,p} Ni,p.这个参数一递归,最多最多只能影响到 u i u_i ui u i + p + 1 u_{i+p+1} ui+p+1这P+2个节点范围内的曲线,因为递归公式中参数的范围就是这个,然后在用阶梯函数吧,一点点线性插值,构成这一段B样条曲线

代码

  • 对于上述的#21的样条曲线,可以用如下代码求解,并将其离散化成32个点
  • 代码和详细注释如下,代码中的t相当于公式中的u,一般是从0到1的参变量
#include <iostream>
#include <vector>
#include <array> 

class Point {
public:
    double x=0;
    double y=0;
};
class NubrsEdge {
public:
    bool ISClOSED=0;

    //B样条曲线的介数,一般为3
    int P;

    //控制点
    std::vector<Point> ControlPoints;

    //节点向量
    std::vector<double> u;

    //利用节点向量计算得到的参数,我们把B样条曲线统一分成32份
    std::vector<std::array<double, 32>> N_p;

     
    //递归计算参数N
    double N(int i,int p,double t) {

        if (p == 0) {
            if (u[i] <= t && t < u[i + 1]) return 1;
            else return 0;
        }
        else{
            double x1 = 0;
           
            //对重复节点的处理!!!!!!!!!!
            //不然就出现除数等于0的情况了
            if (u[i + p] != u[i]) 
            x1 = (t - u[i]) / (u[i + p] - u[i]);

            double x2 = 0;
 			//对重复节点的处理
            if(u[i + p + 1] != u[i + 1])
            x2 = (u[i + p + 1] - t) / (u[i + p + 1] - u[i + 1]);
      
        return x1 * N(i, p - 1, t) + x2 * N(i + 1, p - 1, t);

        }
    }

    //计算参数,$N_{i,p}(u)$
    void calculate_N_p() {
        N_p.resize(ControlPoints.size());
        for (int i = 0; i < ControlPoints.size(); i++) {
            for (int t = 0; t < 32; t++) {
                N_p[i][t] = N(i, P, double(t)/31.00001);
              
            }
        }

    }
    //相当于在做矩阵的乘法
    std::vector<Point> Discretization() {
        calculate_N_p();
        std::vector<Point> result(32);

        for (int t = 0; t < 32; t++) {
            for(int i=0;i < ControlPoints.size(); i++)
            {
                result[t].x += ControlPoints[i].x * N_p[i][t];
                result[t].y += ControlPoints[i].y * N_p[i][t];
          
            }
        }

        return result;
    }
};
int main()
{
    NubrsEdge e;
    // u.size() = 8 = ControlPoints.size + P +1 =4 + 3 + 1
    e.ControlPoints= {
        {-410.738133667533,-34.3141639975569},
        {-360.696916167804,124.126883382823},
        {-317.136530803152,125.95962808178},
        {-280.056977573576,-28.8159299006879}
    };

    e.u = { 0, 0, 0, 0, 1,1,1, 1 };
    e.P = 3;
   
    // 离散化曲线
    std::vector<Point> curvePoints = e.Discretization();

    // 打印结果
    for (int i = 0; i < curvePoints.size(); i++) {
        std::cout << "Point " << i << ": (" << curvePoints[i].x << ", " << curvePoints[i].y << ")" << std::endl;
    }

    return 0;
}
  • 可以发现起始点和结束点与第一个和最后一个控制点重合

在这里插入图片描述


http://www.kler.cn/a/452432.html

相关文章:

  • OSCP课后练习-tcpdump
  • 【Object字段缺失】JS的对象在更新后发现Key值消失
  • 夸克:图片提取文字功能的优秀体验
  • 全国硕士研究生入学考试(考研)常识详解之复试考试科目:笔试、面试与加试
  • UE5.3 C++ Ceiusm中的POI 制作3DUI 结合坐标转化
  • 【day17】多线程基础
  • 【Java基础面试题046】Java中的注解原理是什么?
  • flink sink doris
  • 外包干了两年,技术退步明显...
  • LeetCode每日三題(三
  • shell学习简介(一)
  • 【三维重建】去除瞬态物体Distractor汇总
  • 【行空板K10】评测资料准备
  • 华为OD机试 密码截获(C/JAVA)
  • NNDL 作业11 LSTM
  • FFmpeg在python里推流被处理过的视频流
  • MyBatis如何处理延迟加载?
  • 三维扫描在汽车/航空行业应用
  • Java web的发展历史
  • C#中的委托机制:深入理解与应用