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

,其中-----公式1

Simpson展开后

-------公式2

这里的f(u)就是上面的弧长s的求值函数,既样条曲线拟合函数Q(u)的积分

这部分具体代码如下:1.计算f(u)的系数ABCDE

    CParametric.prototype.SegCoef = function(CSpline, o)
{
p0.x=this.k[0]*CSpline.Spline[o].x+this.k[1]*CSpline.Spline[o+1].x+this.k[2]*CSpline.Spline[o+2].x+this.k[3]*CSpline.Spline[o+3].x;
p1.x=this.k[4]*CSpline.Spline[o].x+this.k[5]*CSpline.Spline[o+1].x+this.k[6]*CSpline.Spline[o+2].x+this.k[7]*CSpline.Spline[o+3].x;
p2.x=this.k[8]*CSpline.Spline[o].x+this.k[9]*CSpline.Spline[o+1].x+this.k[10]*CSpline.Spline[o+2].x+this.k[11]*CSpline.Spline[o+3].x;
p3.x=this.k[12]*CSpline.Spline[o].x+this.k[13]*CSpline.Spline[o+1].x+this.k[14]*CSpline.Spline[o+2].x+this.k[15]*CSpline.Spline[o+3].x; p0.y=this.k[0]*CSpline.Spline[o].y+this.k[1]*CSpline.Spline[o+1].y+this.k[2]*CSpline.Spline[o+2].y+this.k[3]*CSpline.Spline[o+3].y;
p1.y=this.k[4]*CSpline.Spline[o].y+this.k[5]*CSpline.Spline[o+1].y+this.k[6]*CSpline.Spline[o+2].y+this.k[7]*CSpline.Spline[o+3].y;
p2.y=this.k[8]*CSpline.Spline[o].y+this.k[9]*CSpline.Spline[o+1].y+this.k[10]*CSpline.Spline[o+2].y+this.k[11]*CSpline.Spline[o+3].y;
p3.y=this.k[12]*CSpline.Spline[o].y+this.k[13]*CSpline.Spline[o+1].y+this.k[14]*CSpline.Spline[o+2].y+this.k[15]*CSpline.Spline[o+3].y; this.A=9*(p0.x*p0.x+p0.y*p0.y);
this.B=12*(p0.x*p1.x+p0.y*p1.y);
this.C=6*(p0.x*p2.x+p0.y*p2.y)+4*(p1.x*p1.x+p1.y*p1.y);
this.D=4*(p1.x*p2.x+p1.y*p2.y);
this.E=p2.x*p2.x+p2.y*p2.y;
}

这里的k数组是Cardinal样条曲线的Mc矩阵,具体内容可以参考Cardinal样条曲线的Javascript实现(理论篇)。这里的p0,p1,p2,p3就是公式1里的ax,ay,bx,by,cx,cy,dx,dy。从而求得积分函数系数。

2.计算扩展的Simpson方法展开后得到的积分函数

    CParametric.prototype.ArcLength = function(ustart, uend){
var h,sum,u;
var i;
h=(uend-ustart)*1.0/ITERATION_COUNT; //扩展的Simposon方法的阶数
sum=0;
u=ustart+h; for(var i=2; i <= ITERATION_COUNT; i++){
if(!(i&1)){
sum += 4.0*this.ArcIntergrand(u);
}
else{
sum += 2.0*this.ArcIntergrand(u);
}
u += h;
}
return(h*this.ArcIntergrand(ustart)+sum+this.ArcIntergrand(uend)/3.0);
}

这里的ITERATION_COUNT是扩展的Simposon方法的阶数,既公式2中的n,其中的ArcIntergrand(u)就是求fi的值,代码如下:

    CParametric.prototype.ArcIntergrand = function(u)
{
var f;
f=this.A*u*u*u*u+this.B*u*u*u+this.C*u*u+this.D*u+this.E;
f=Math.sqrt(f);
return f;
}

3.建立s-u索引表

上面的积分函数只能得到没一个曲线段上一个u对应s的值,而一整条样条曲线由多个小曲线段组成,比如计算第二段曲线上累加的s的值的时候只要把前面那段曲线的总长作为一个基数加上去就可以了。建立了s-u索引表之后就可以用二分法来查找每个给定的s对应的u的值了。因为这个函数是严格单调递增的,所以这个索引表肯定是升序的,就可以用二分法来查找。具体代码如下:

    CParametric.prototype.SetLengths = function(spline, npoints){
var no_segments; //u分割的精度
var arcLength;
this.seg_lengths = new Array(); no_segments = npoints-3;
arcLength = 0; this.seg_lengths[0]=0;
for(var i=0; i<no_segments; i++){
this.SegCoef(spline, i);
arcLength += this.ArcLength(0.,1.); //ArcLength(0,1)就是前面一个曲线段的总长
this.seg_lengths[i+1] = arcLength;
}
this.total_length = arcLength;
for(var i=1; i<no_segments; i++){
this.seg_lengths[i] /= this.total_length; //s归一化
}
}

因为弧长累加的值较大,所以对其进行归一化之后可以得到更标准的弧长值。

4.二分法计算弧长为seg的曲线上的点的位置pt

    CParametric.prototype.ArcLengthPoint = function(spline, seg){
var uL=0., uR=1., usearch;
var segment_dist, ssearch;
var segment_no=0; do{
segment_no++;
}while(this.seg_lengths[segment_no] < seg);
segment_no --;
segment_dist = this.total_length*(s-this.seg_lengths[segment_no]); this.SegCoef(spline,segment_no); do{
usearch = (uL+uR)/2;
ssearch = this.ArcLength(uL, usearch); if(segment_dist < ssearch+SEARCH_TOL){
uR=usearch;
}
else{
uL=usearch;
segment_dist -= ssearch;
}
}while((segment_dist>ssearch+SEARCH_TOL) || (segment_dist<ssearch-SEARCH_TOL));
this.GetPointOnSpline(usearch); };

就是普通的二分查找法,给定一个弧长seg,在函数曲线上找到对应的u的值,返回的usearch就是在指定精度var SEARCH_TOL=0.5(可以任意指定)的情况下得到的u的值。再通过调用this.GetPointOnSpline(usearch)函数来计算u=usearch时对应的Q(u)的值。

    CParametric.prototype.GetPointOnSpline=function(usearch){
this.pt[pointnum]= new CPT();
this.pt[pointnum].x=p0.x*usearch*usearch*usearch+p1.x*usearch*usearch+p2.x*usearch+p3.x;
this.pt[pointnum].y=p0.y*usearch*usearch*usearch+p1.y*usearch*usearch+p2.y*usearch+p3.y;
}

曲线参数化的Javascript实现(代码篇)的更多相关文章

  1. 曲线参数化的Javascript实现(理论篇)

    在关键帧动画的制作过程中,动画师在k物体运动的过程中,一般要确定2个参数: 1)运动轨迹(表示物体运动的路径): 2)速度曲线(表示物体随时间的速度变化). 对于运动轨迹通常选用一定的样条曲线,通过动 ...

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

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

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

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

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

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

  5. JavaScript standard 代码规范的全文

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

  6. JavaScript性能优化篇js优化

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

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

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

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

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

  9. javascript两行代码按指定格式输出日期时间

    javascript两行代码按指定格式输出日期时间,具体看代码: function date2str(x,y) { var z ={y:x.getFullYear(),M:x.getMonth()+1 ...

随机推荐

  1. virtualbox虚拟机中的centos与macos共享文件夹

    开发中需要用到linux环境,所以使用共享模式开发.通过samba服务器来实现. 环境: 虚拟机 virtualbox 虚拟系统 centos 6.6 本机 macos  192.168.1.102 ...

  2. 获取$(this)子节点对象的方法

    获取$(this)子节点对象的方法: 1.children()方法: children() 方法返回被选元素的所有直接子元素. 该方法只会向下一级对 DOM 树进行遍历. 2.find()方法: fi ...

  3. TypeError: coercing to Unicode: need string or buffer, ChatRoom found

    在用django框架中遇到一个错误,是模型编写中出的错误 TypeError: coercing to Unicode: need string or buffer, ChatRoom found 解 ...

  4. Sprint 2

    成员 团队贡献分 许佳仪 22 柯晓君 23 卓宇靖 18 赖文亮 17 浏览书籍 查询书籍(可分别按照图书名和价格进行查询)

  5. 再战江湖。vuforia 初试

    AR 里发现一个可用的项目  vuforia,  试着用用. 也是在很久不写博客后(以前全在百度博客上) 再次写

  6. jquery 中 $.map 的使用方法

    $.map(data,function(item,index){return XXX}) 遍历data数组中的每个元素,并按照return中的计算方式 形成一个新的元素,放入返回的数组中 ,,], f ...

  7. Sql:多行合并一行以及多条数据取时间最早的那条

    有两个导数据的需求,1.一张表里面每一个订单号可能对应多条数据,每个单号返回时间最早的那条. 2.根据条件查询某个字段并按照逗号,合并在一起. 表类似结构如下: 第一条sql:select c.Id, ...

  8. C++调用约定和名字约定

    C++调用约定和名字约定 转自http://www.cppblog.com/mzty/archive/2007/04/20/22349.html 调用约定:__cdecl __fastcall与 __ ...

  9. 立体角的单位——立体弧度(sr)

    国际单位制(SI)中,关于物理量 发光强度 的介绍: 1cd(坎德拉)为一光源在给定方向的发光强度,该光源发出频率为540×1012Hz(赫兹)的单色辐射,且在此方向上的辐射强度为 1/683 W/s ...

  10. Centos 6.5 安装 ionCube PHP Loader

    使用某些php的程序的时候会出现提示:Site error: the file /***/index.php requires the ionCube PHP Loader ioncube_loade ...