由上一篇文章得到了Cardinal曲线的矩阵表达式,下面就这个矩阵表达式就可以来对曲线进行插值了。

这里选用了JS来实现,完全是因为之前交作业的时候还不知道怎么在Xcode里建完整的C++OpenGL的项目,所以就用js在浏览器这个最大的跨平台UI上写。。

先看之前得到的Cardinal插值的样条曲线的矩阵,对每一段曲线PkPk+1来说,都可以通过拟合一个被参数化为P(u)函数(0<= u <=1)的图形的形式:

,其中

同样,M*P得到的是系数矩阵[a b c d]的转置,s是引入的表示每个连接点处曲线尖锐程度的变量-张量

所以我们现在的期望是

输入:n个控制点的xy轴坐标数组x[],y[],张量tension,每两个控制点之间插入的密度grain

输出:插值好的样条曲线上控制点的一个数组

1.构造函数 function CSpline(x, y, grain, tension, n)

拥有的成员变量和成员函数:

function CSpline(x, y, grain, tension, n) {
var jd = new Array(100); //用户输入的控制点位置数组,临时变量存储
this.n0=n; //控制点个数
this.m = new Array(16); //Mc矩阵
this.Spline = new Array(1024); //插值好的控制点数组
CSpline.prototype.GetCardinalMatrix = function(a1) {} //通过给定的tension值生成Mc矩阵
CSpline.prototype.Matrix = function(a, b, c, d, u){} //计算P(u)的值,xy分量均相同
CSpline.prototype.CubicSpline = function(np, knots, grain, tension) {} //插值函数 //临时函数,建立曲线控制点数组jd,并调用CubicSpline函数计算插值曲线
function CSpline(x, y, grain, tension, n)
{
for(var i=1; i<=np; i++){
  jd[i] = new CPT(x[i-1],y[i-1]); //内部点
}
jd[0] = new CPT(x[0],y[0]); //补上隐含的整条曲线起始点
jd[np+1] = new CPT(x[np-1],y[np-1]); //补上隐含的整条曲线终止点
np=np+2;
this.CubicSpline(np, jd, grain, tension);
}
}

这里成员变量通过构造函数分别在实例中存储,而成员函数则在对应的原型函数中存储。

2.计算Mc矩阵函数GetCardinalMatrix = function(a1)

根据输入的平滑度 tension 值计算Mc矩阵

CSpline.prototype.GetCardinalMatrix = function(a1) {
this.m[0]=-a1; this.m[1]=2.0-a1; this.m[2]=a1-2.; this.m[3]=a1;
this.m[4]=2.*a1; this.m[5]=a1-3.; this.m[8]=-a1; this.m[9]=0.;
this.m[12]=0.; this.m[13]=1.; this.m[6]=3.-2*a1; this.m[7]=-a1;
this.m[10]=a1; this.m[11]=0.; this.m[14]=0.; this.m[15]=0.;
}

这里m是一个4*4的矩阵,a1表示tension值

3.计算P(u)的值

输入4个点Pk-1,Pk,Pk+1,Pk+2的值(x分量或者y分量,以及参数化好的u值),返回计算得到的P(u)的值

CSpline.prototype.Matrix = function(p0, p1, p2, p3, u){
//求解系数
var a, b, c, d;
a=this.m[0]*p0+this.m[1]*p1+this.m[2]*p2+this.m[3]*p3;
b=this.m[4]*p0+this.m[5]*p1+this.m[6]*p2+this.m[7]*p3;
c=this.m[8]*p0+this.m[9]*p1+this.m[10]*p2+this.m[11]*p3;
d=this.m[12]*p0+this.m[13]*p1+this.m[14]*p2+this.m[15]*p3;
return(d+u*(c+u*(b+u*a))); //au^3+bu^2+cu+d
}

4.主要绘制函数CSpline.prototype.CubicSpline = function(np, knots, grain, tension)

CSpline.prototype.CubicSpline = function(np, knots, grain, tension) {
alpha = new Array(50);
var k0, kml, k1, k2;
//获取Mc矩阵
this.GetCardinalMatrix(tension);
//对每两个关键点之间的插值点进行参数化到0~1之间
for(var i=0; i<grain; i++){
alpha[i]=i*1.0/grain;
}
//从最开始的四个点开始,给第一段曲线插值
kml = 0;
k0 = 1;
k1 = 2;
k2 = 3;
this.s = 0; //纪录总共插值后的点数
//两次循环第一次对输入的控制点遍历,第二次对每两个控制点之间插值,分别计算xy分量上得出的插值后的函数值,k值分别+1
for(var i =1; i<this.n0; i++){
for(var j=0; j<grain; j++){
cpx = this.Matrix(knots[kml].x, knots[k0].x, knots[k1].x, knots[k2].x, alpha[j]);
cpy = this.Matrix(knots[kml].y, knots[k0].y, knots[k1].y, knots[k2].y, alpha[j]);
this.Spline[this.s] = new CPT(cpx, cpy);
this.s++;
}
kml++; k0++; k1++; k2++;
}
}

最后的结果截图如下:

完整的代码正在上传github。。

Cardinal样条曲线的Javascript实现(代码篇)的更多相关文章

  1. Cardinal样条曲线的Javascript实现(理论篇)

    首先,要对样条曲线进行插值的原因是:希望通过给定的关键帧点生成一条希望的直线或者曲线. 1.直线插值 生成一条直线,给定直线首尾的关键点P0,P1,就能确定这条直线的特性,比如y=kx+b中的斜率k和 ...

  2. 曲线参数化的Javascript实现(代码篇)

    在曲线参数化的Javascript实现(理论篇)中推出了曲线弧长积分的公式,以及用二分法通过弧长s来查找样条曲线上对应的u,再求Q(u)的值.弧长积分函数如下: ,其中-----公式1 Simpson ...

  3. Javascript本质第二篇:执行上下文

    在上一篇文章<Javascript本质第一篇:核心概念>中,对Javascript执行上下文做了解释,但是这些都是基于Javascript标准中对执行上下文的定义,也就是说理论上的东西,本 ...

  4. JavaScript 精髓整理篇之一(对象篇)postby:http://zhutty.cnblogs.com

    废话篇头: 由于工作关系,所以写博文的时间有那么点~~,其实是输入法太懒了,都是输入法的错~~ 这一系列的博客将总结所有关于JavaScript语言的精髓,适合0基础到大师级别人物阅读. <Ja ...

  5. 32、可以拿来用的JavaScript实用功能代码

    可以拿来用的JavaScript实用功能代码(可能会有些bug,用时稍微修改下,我用了几个还可以) 转载自 1.原生JavaScript实现字符串长度截取 function cutstr(str, l ...

  6. JavaScript standard 代码规范的全文

    这是 JavaScript standard 代码规范的全文. 掌握本规范的最好方法是安装并在自己的代码中使用它. 细则 使用两个空格进行缩进. eslint: indent function hel ...

  7. JavaScript性能优化篇js优化

    JavaScript性能优化篇js优化   随着Ajax越来越普遍,Ajax引用的规模越来越大,Javascript代码的性能越来越显得重要,我想这就是一个很典型的例子,上面那段代码因为会被频繁使用, ...

  8. rcGIS API for JavaScript之基础篇(一)

    ArcGIS API for JavaScript之基础篇(一)上一篇文章介绍了ArcGIS 10.4的安装指南也包含了所需要资源,需要的同学可以去公众号中查找.最近几天学习了2D地图.3D地图以及图 ...

  9. TODO:一不顺眼就换字体Go之代码篇

    TODO:一不顺眼就换字体Go之代码篇 image包实现了一个基本的2D图像库,该包中包含基本的接口叫做image,这个里面包含color,这个将在image/color中描述:新增字体font,进行 ...

随机推荐

  1. 正则表达式入门(六)匹配unicode和其他字符

    匹配unicode字符有时候我们需要匹配ASCII范围之外的字符. "Qu'est-ce que la tolérance? c'est l'apanage de l'humanité. N ...

  2. python——线程与多线程基础

    我们之前已经初步了解了进程.线程与协程的概念,现在就来看看python的线程.下面说的都是一个进程里的故事了,暂时忘记进程和协程,先来看一个进程中的线程和多线程.这篇博客将要讲一些单线程与多线程的基础 ...

  3. CentOS下 MySQL5.7 详细的部署安装流程

    MySQL5.7.14安装过程: 下载5.7版本:wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.14-linux-glibc2 ...

  4. php crc32,md5,sha1,mhash测试结果

    总结:php  自带hash mhash 用于散列只能加密   扩展mcrypt 用于加解密 对文件加密有的文件会隐藏换行,或者读取方式等影响导致结果不一致. 1.crc32 php: a.系统crc ...

  5. sql sever读取Excel总结【转】

    主要用到openrowset,opendatasource系统函数,这两个函数任意一个都能完成任务 用这种方法可以实现Excel和sqlserver表之间的相互导入导出. openrowset的写法 ...

  6. [原创]VM虚拟机Centos6.4网络配置。

    关于虚拟机VMware 3种网络模式(桥接.nat.Host-only)的工作原理http://www.cnblogs.com/hehexiaoxia/p/4042583.html 操作环境 主机:W ...

  7. 数据类型、常量、变量、printf、scanf和运算符

    数据类型 常量 变量 printf函数介绍 scanf函数介绍 运算符 数据类型 数据类型是指数据在内存中存储的方式. C语言中有5大数据类型:基本类型.构造类型.指针类型.空类型.定义类型. C语言 ...

  8. Rendering Problems:android.support.v7.internal.widget.ActionBarOverlayLayout 解决方法

    不知道是不是android studio安装不对的问题,每次新建项目都有这个问题. 临时解决方法是: 打开 styles.xml 在Theme.AppCompat.Light.DarkActionBa ...

  9. virtual_login

    from selenium import webdriverimport timedriver = webdriver.Chrome()driver.set_window_position(30, 4 ...

  10. My Game --文件读取数据

    My Game --线段数据 中说到背景的绘制由贝赛尔曲线生成线段,用 DrawNode 画多边形,同时一张背景有两座山,一座山有两条以上贝赛尔曲线保存,用了嵌套的数据类:Bezier,LineLay ...