three.js 源码注释(十九)Math/Spline.js

102 篇文章 13 订阅
100 篇文章 3 订阅

商域无疆 (http://blog.csdn.net/omni360/)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化、GOLANG、Html5、WEBGL、THREE.JS否则,出自本博客的文章拒绝转载或再转载,谢谢合作。


俺也是刚开始学,好多地儿肯定不对还请见谅.

以下代码是THREE.JS 源码文件中Math/Spline.js文件的注释.

更多更新在 : https://github.com/omni360/three.js.sourcecode


/**
 * Spline from Tween.js, slightly optimized (and trashed)
 * http://sole.github.com/tween.js/examples/05_spline.html
 *
 * @author mrdoob / http://mrdoob.com/
 * @author alteredq / http://alteredqualia.com/
 */

/*
///Spline对象的构造函数.用来在三维空间内通过参数points(Vector3数组)创建一个样条曲线对象..
///
///	定义:样条曲线是经过一系列给定点的光滑曲线。最初,样条曲线都是借助于物理样条得到的,放样员把富有弹性的细木条(或有机玻璃条),
///		 用压铁固定在曲线应该通过的给定型值点处,样条做自然弯曲所绘制出来的曲线就是样条曲线。样条曲线不仅通过各有序型值点,
///		 并且在各型值点处的一阶和二阶导数连续,也即该曲线具有连续的、曲率变化均匀的特点。
///	NOTE:参考百度百科http://baike.baidu.com/view/1896463.htm?fr=aladdin
/// NOTE:关于三次样条插值,参考百度百科http://baike.baidu.com/view/2326225.htm?fr=aladdin
/// NOTE:关于更多样条曲线插值,参考维基百科http://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A
/// NOTE:关于样条曲线,参考维基百科http://zh.wikipedia.org/wiki/%E6%A0%B7%E6%9D%A1%E5%87%BD%E6%95%B0
///
///
///	用法: var a = new Vector3(0,0,0),b = new Vector3(1,1,1),c = new Vector3(2,2,2); var points = new Array(a,b,c); var spline = new Spline(points);
///创建一个a,b,c三点组成的样条曲线对象.
*/
///<summary>Spline</summary>
///<param name ="points" type="Vector3Array">Vector3对象组成的points数组对象</param>
THREE.Spline = function ( points ) {

	this.points = points;	//将参数points设置给当前样条对象的points属性

	var c = [], v3 = { x: 0, y: 0, z: 0 },
	point, intPoint, weight, w2, w3,
	pa, pb, pc, pd;

	/****************************************
	****下面是Spline对象提供的功能函数.
	****************************************/

	/*
	///initFromArray方法通过Vector3对象组成的数组(参数a),重新设置当前样条曲线.
	*/
	///<summary>initFromArray</summary>
	///<param name ="a" type="Vector3Array">Vector3对象组成的points数组对象</param>
	///<returns type="Spline">返回新的样条曲线</returns>
	this.initFromArray = function ( a ) {

		this.points = [];

		for ( var i = 0; i < a.length; i ++ ) {	//获得数组长度,并将数组中元素赋值给当前样条曲线的points属性.

			this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] };

		}

	};

	/*
	///getPoint方法将当前样条曲线作为一个整体,返回位于当前样条曲线k位置上的点坐标.
	/// NOTE:getPoint()方法中k值取值范围是0.0-1.0.
	*/
	///<summary>getPoint</summary>
	///<param name ="k" type="Float">返回位于当前样条曲线k位置上的点坐标</param>
	///<returns type="Spline">返回新的样条曲线</returns>
	this.getPoint = function ( k ) {

		point = ( this.points.length - 1 ) * k;	//获得k大概位于当前样条曲线的第几个节点后,得出结果可能是小数(例如样条曲线有9个节点,参数k为0.4,得出结果3.2说明参数k位于当前样条曲线第三个节点到第四个节点长度20%的位置),赋值给point
		intPoint = Math.floor( point );		//调用Math.floor()方法,获得整数,第三个节点,赋值给intPoint
		weight = point - intPoint;	//或得权值,赋值给weight

		c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;	//三次样条曲线的起始点c[0]
		c[ 1 ] = intPoint;	//三次样条曲线的控制点c[1]
		c[ 2 ] = intPoint  > this.points.length - 2 ? this.points.length - 1 : intPoint + 1;	//三次样条曲线的控制点c[2]
		c[ 3 ] = intPoint  > this.points.length - 3 ? this.points.length - 1 : intPoint + 2;	//三次样条曲线的结束点c[3]

		pa = this.points[ c[ 0 ] ];
		pb = this.points[ c[ 1 ] ];
		pc = this.points[ c[ 2 ] ];
		pd = this.points[ c[ 3 ] ];

		w2 = weight * weight;	//权值的平方
		w3 = weight * w2;	//权值的立方

		v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 );	//调用interpolate方法是样条插值函数,返回计算位于参数值t的曲线点x坐标
		v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 );	//调用interpolate方法是样条插值函数,返回计算位于参数值t的曲线点y坐标
		v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 );	//调用interpolate方法是样条插值函数,返回计算位于参数值t的曲线点z坐标

		return v3;	//返回位于当前样条曲线k位置上的点坐标

	};

	/*
	///getControlPointsArray方法返回当前样条曲线节点坐标构成的数组
	*/
	///<summary>getControlPointsArray</summary>
	///<returns type="Vector3Array">返回当前样条曲线节点坐标构成的数组</returns>
	this.getControlPointsArray = function () {

		var i, p, l = this.points.length,
			coords = [];

		for ( i = 0; i < l; i ++ ) {	//遍历当前样条曲线points属性

			p = this.points[ i ];
			coords[ i ] = [ p.x, p.y, p.z ];	//将points属性直接赋值给coords数组

		}

		return coords;	//返回当前样条曲线节点坐标构成的数组

	};



	/*
	///getLength方法返回被参数nSubDivisions(将当前样条曲线等分成多少段)等分当前样条曲线的长度数组和总长度组成的对象.
	*/
	///<summary>getLength</summary>
	///<param name ="nSubDivisions" type="Number">分段数</param>
	///<returns type="Spline">返回被参数nSubDivisions(将当前样条曲线等分成多少段)等分当前样条曲线的长度数组和总长度组成的对象</returns>
	// approximate length by summing linear segments
	//汇总线性线段获得近似长度

	this.getLength = function ( nSubDivisions ) {

		var i, index, nSamples, position,
			point = 0, intPoint = 0, oldIntPoint = 0,
			oldPosition = new THREE.Vector3(),
			tmpVec = new THREE.Vector3(),
			chunkLengths = [],
			totalLength = 0;

		// first point has 0 length
		// 第一个起点长度是0

		chunkLengths[ 0 ] = 0;

		if ( ! nSubDivisions ) nSubDivisions = 100;

		nSamples = this.points.length * nSubDivisions;

		oldPosition.copy( this.points[ 0 ] );

		for ( i = 1; i < nSamples; i ++ ) {

			index = i / nSamples;

			position = this.getPoint( index );	//调用getPoint()方法,获得当前段数的位置坐标.
			tmpVec.copy( position );

			totalLength += tmpVec.distanceTo( oldPosition );	//求当前段数长度.

			oldPosition.copy( position );

			point = ( this.points.length - 1 ) * index;
			intPoint = Math.floor( point );

			if ( intPoint != oldIntPoint ) {

				chunkLengths[ intPoint ] = totalLength;
				oldIntPoint = intPoint;

			}

		}

		// last point ends with total length
		//最后一个结束点,返回总长度.

		chunkLengths[ chunkLengths.length ] = totalLength;

		return { chunks: chunkLengths, total: totalLength };

	};

	this.reparametrizeByArcLength = function ( samplingCoef ) {

		var i, j,
			index, indexCurrent, indexNext,
			linearDistance, realDistance,
			sampling, position,
			newpoints = [],
			tmpVec = new THREE.Vector3(),
			sl = this.getLength();

		newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() );

		for ( i = 1; i < this.points.length; i ++ ) {

			//tmpVec.copy( this.points[ i - 1 ] );
			//linearDistance = tmpVec.distanceTo( this.points[ i ] );

			realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ];

			sampling = Math.ceil( samplingCoef * realDistance / sl.total );

			indexCurrent = ( i - 1 ) / ( this.points.length - 1 );
			indexNext = i / ( this.points.length - 1 );

			for ( j = 1; j < sampling - 1; j ++ ) {

				index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent );

				position = this.getPoint( index );
				newpoints.push( tmpVec.copy( position ).clone() );

			}

			newpoints.push( tmpVec.copy( this.points[ i ] ).clone() );

		}

		this.points = newpoints;

	};

	// Catmull-Rom

	/*
	///interpolate方法是传说中的样条插值函数,这里是三次样条插值算法,返回计算位于参数值t的曲线点.
	/// NOTE:关于三次样条插值,参考百度百科http://baike.baidu.com/view/2326225.htm?fr=aladdin
	/// NOTE:关于更多样条曲线插值,参考维基百科http://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A
	///										  http://zh.wikipedia.org/wiki/%E6%A0%B7%E6%9D%A1%E6%8F%92%E5%80%BC
	/// NOTE:关于样条曲线,参考维基百科http://zh.wikipedia.org/wiki/%E6%A0%B7%E6%9D%A1%E5%87%BD%E6%95%B0
	*/
	///<summary>interpolate</summary>
	///<param name ="p0" type="Float">样条曲线起始点p0</param>
	///<param name ="p1" type="Float">样条曲线控制点p1</param>
	///<param name ="p2" type="Float">样条曲线控制点p2</param>
	///<param name ="p3" type="Float">样条曲线结束点p3</param>
	///<param name ="t" type="Float">t为参数值,0<=t<=1</param>
	///<param name ="t2" type="Float">t2是参数值t的平方</param>
	///<param name ="t3" type="Float">t3是参数值t的立方</param>
	///<returns type="Spline">返回计算位于参数值t的曲线点</returns>
	function interpolate( p0, p1, p2, p3, t, t2, t3 ) {

		var v0 = ( p2 - p0 ) * 0.5,
			v1 = ( p3 - p1 ) * 0.5;

		return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;		//返回计算位于参数值t的曲线点

	};

};


商域无疆 (http://blog.csdn.net/omni360/)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:商域无疆 -  本博客专注于 敏捷开发及移动和物联设备研究:数据可视化、GOLANG、Html5、WEBGL、THREE.JS否则,出自本博客的文章拒绝转载或再转载,谢谢合作。


以下代码是THREE.JS 源码文件中Math/Spline.js文件的注释.

更多更新在 : https://github.com/omni360/three.js.sourcecode

#include <iostream> #include <cmath> #include <fstream> using namespace std; class scyt { float *x,*y,*d,*h,*u,*q,*a,*b,*c,*l,*r,*o,*M; int m; float y0,y3; public: scyt(); void qiudao(); void zgf(); void qiujie(); ~scyt(); }; void main() { scyt hello; hello.qiudao(); hello.zgf(); hello.qiujie(); } scyt::scyt() { ifstream fin("三次样条插值.txt"); for(float j;fin>>j;) { m=int(j); break; } x=new float[m]; y=new float[m]; d=new float[m]; h=new float[m-1]; u=new float[m-2]; q=new float[m-2]; a=new float[m-1]; b=new float[m]; c=new float[m-1]; l=new float[m]; r=new float[m-1];//此处的r为追赶法中的u; o=new float[m];//此处o为追赶法中的y M=new float[m];//此处M为追赶法中的x; int jishu=0; for(j;fin>>j;) { if(jishu<=m-1) x[jishu]=j; if(jishu>m-1&&jishu;<2*m) { y[jishu-m]=j; } if(jishu==2*m) { y0=j; } if(jishu==2*m+1) { y3=j; } jishu++; } fin.close(); } void scyt::qiudao() { for(int i=0;i<m-1;i++) { h[i]=x[i+1]-x[i]; } for(i=0;i<m-2;i++) { u[i]=h[i] / (h[i] + h[i+1]); } for(i=0;i<m-2;i++) { q[i]=1-u[i]; } d[0]=6/h[0]*((y[1]-y[0])/h[0]-y0); for(i=1;i<m-1;i++) { d[i]=6/(h[i-1]+h[i])*((y[i+1]-y[i])/h[i]-((y[i]-y[i-1])/h[i-1])); } d[m-1]=6/h[m-2]*(y3-(y[m-1]-y[m-2])/h[m-2]); } void scyt::zgf() { u[m-2]=1; for(int i=0;i<m;i++) { b[i]=2; } c[0]=1; for(i=1;i<m-1;i++) { c[i]=q[i-1]; } //........................................ l[0]=b[0]; for(i=0;i<m-1;i++) { r[i]=c[i] / l[i]; l[i+1]=b[i+1] - (u[i] * r[i]); } o[0]=d[0] / l[0]; for(i=1;i<m;i++) { o[i]=(d[i]-u[i-1]*o[i-1]) / l[i]; } M[m-1]=o[m-1]; for(i=m-2;i>=0;i--) { M[i]=o[i]-r[i] * M[i+1]; } cout<<m<<"个点的导数值分别是:"<<endl; for(i=0;i<m;i++) { cout<<"M"<<i+1<<"="; cout<<M[i]<<endl; } //M的值求出。。。。。。追赶法调用完毕 } void scyt::qiujie() { float S; for(;;) { float f; cout<<"请输入待求x的值(输入1000)时退出:"; cin>>f; if(f==1000) break; for(int i=0;i<m;i++) { if(f>x[i]&&f<x[i+1]) { S=pow((x[i+1]-f),3)*M[i]/(6*h[i]) + pow(f-x[i],3)*M[i+1]/(6*h[i]) + (x[i+1]-f)*(y[i]-h[i]*h[i]*M[i]/6)/h[i] + (f-x[i])*(y[i+1]-h[i]*h[i]*M[i+1]/6)/h[i]; cout<<"S["<<f<<"]="<<S<<endl; } } } } scyt::~scyt() { delete []x,y,d,h,u,q,a,b,c,l,r,o,M; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值