Spline.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { Vector3 } from './Vector3';
  2. /**
  3. * Spline from Tween.js, slightly optimized (and trashed)
  4. * http://sole.github.com/tween.js/examples/05_spline.html
  5. *
  6. * @author mrdoob / http://mrdoob.com/
  7. * @author alteredq / http://alteredqualia.com/
  8. */
  9. function Spline( points ) {
  10. this.points = points;
  11. var c = [], v3 = { x: 0, y: 0, z: 0 },
  12. point, intPoint, weight, w2, w3,
  13. pa, pb, pc, pd;
  14. this.initFromArray = function ( a ) {
  15. this.points = [];
  16. for ( var i = 0; i < a.length; i ++ ) {
  17. this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] };
  18. }
  19. };
  20. this.getPoint = function ( k ) {
  21. point = ( this.points.length - 1 ) * k;
  22. intPoint = Math.floor( point );
  23. weight = point - intPoint;
  24. c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
  25. c[ 1 ] = intPoint;
  26. c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1;
  27. c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2;
  28. pa = this.points[ c[ 0 ] ];
  29. pb = this.points[ c[ 1 ] ];
  30. pc = this.points[ c[ 2 ] ];
  31. pd = this.points[ c[ 3 ] ];
  32. w2 = weight * weight;
  33. w3 = weight * w2;
  34. v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 );
  35. v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 );
  36. v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 );
  37. return v3;
  38. };
  39. this.getControlPointsArray = function () {
  40. var i, p, l = this.points.length,
  41. coords = [];
  42. for ( i = 0; i < l; i ++ ) {
  43. p = this.points[ i ];
  44. coords[ i ] = [ p.x, p.y, p.z ];
  45. }
  46. return coords;
  47. };
  48. // approximate length by summing linear segments
  49. this.getLength = function ( nSubDivisions ) {
  50. var i, index, nSamples, position,
  51. point = 0, intPoint = 0, oldIntPoint = 0,
  52. oldPosition = new Vector3(),
  53. tmpVec = new Vector3(),
  54. chunkLengths = [],
  55. totalLength = 0;
  56. // first point has 0 length
  57. chunkLengths[ 0 ] = 0;
  58. if ( ! nSubDivisions ) nSubDivisions = 100;
  59. nSamples = this.points.length * nSubDivisions;
  60. oldPosition.copy( this.points[ 0 ] );
  61. for ( i = 1; i < nSamples; i ++ ) {
  62. index = i / nSamples;
  63. position = this.getPoint( index );
  64. tmpVec.copy( position );
  65. totalLength += tmpVec.distanceTo( oldPosition );
  66. oldPosition.copy( position );
  67. point = ( this.points.length - 1 ) * index;
  68. intPoint = Math.floor( point );
  69. if ( intPoint !== oldIntPoint ) {
  70. chunkLengths[ intPoint ] = totalLength;
  71. oldIntPoint = intPoint;
  72. }
  73. }
  74. // last point ends with total length
  75. chunkLengths[ chunkLengths.length ] = totalLength;
  76. return { chunks: chunkLengths, total: totalLength };
  77. };
  78. this.reparametrizeByArcLength = function ( samplingCoef ) {
  79. var i, j,
  80. index, indexCurrent, indexNext,
  81. realDistance,
  82. sampling, position,
  83. newpoints = [],
  84. tmpVec = new Vector3(),
  85. sl = this.getLength();
  86. newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() );
  87. for ( i = 1; i < this.points.length; i ++ ) {
  88. //tmpVec.copy( this.points[ i - 1 ] );
  89. //linearDistance = tmpVec.distanceTo( this.points[ i ] );
  90. realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ];
  91. sampling = Math.ceil( samplingCoef * realDistance / sl.total );
  92. indexCurrent = ( i - 1 ) / ( this.points.length - 1 );
  93. indexNext = i / ( this.points.length - 1 );
  94. for ( j = 1; j < sampling - 1; j ++ ) {
  95. index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent );
  96. position = this.getPoint( index );
  97. newpoints.push( tmpVec.copy( position ).clone() );
  98. }
  99. newpoints.push( tmpVec.copy( this.points[ i ] ).clone() );
  100. }
  101. this.points = newpoints;
  102. };
  103. // Catmull-Rom
  104. function interpolate( p0, p1, p2, p3, t, t2, t3 ) {
  105. var v0 = ( p2 - p0 ) * 0.5,
  106. v1 = ( p3 - p1 ) * 0.5;
  107. return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
  108. }
  109. }
  110. export { Spline };