CurvePath.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import { Curve } from './Curve.js';
  2. import { LineCurve } from '../curves/LineCurve.js';
  3. /**
  4. * @author zz85 / http://www.lab4games.net/zz85/blog
  5. *
  6. **/
  7. /**************************************************************
  8. * Curved Path - a curve path is simply a array of connected
  9. * curves, but retains the api of a curve
  10. **************************************************************/
  11. function CurvePath() {
  12. Curve.call( this );
  13. this.curves = [];
  14. this.autoClose = false; // Automatically closes the path
  15. }
  16. CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), {
  17. constructor: CurvePath,
  18. add: function ( curve ) {
  19. this.curves.push( curve );
  20. },
  21. closePath: function () {
  22. // Add a line curve if start and end of lines are not connected
  23. var startPoint = this.curves[ 0 ].getPoint( 0 );
  24. var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
  25. if ( ! startPoint.equals( endPoint ) ) {
  26. this.curves.push( new LineCurve( endPoint, startPoint ) );
  27. }
  28. },
  29. // To get accurate point with reference to
  30. // entire path distance at time t,
  31. // following has to be done:
  32. // 1. Length of each sub path have to be known
  33. // 2. Locate and identify type of curve
  34. // 3. Get t for the curve
  35. // 4. Return curve.getPointAt(t')
  36. getPoint: function ( t ) {
  37. var d = t * this.getLength();
  38. var curveLengths = this.getCurveLengths();
  39. var i = 0;
  40. // To think about boundaries points.
  41. while ( i < curveLengths.length ) {
  42. if ( curveLengths[ i ] >= d ) {
  43. var diff = curveLengths[ i ] - d;
  44. var curve = this.curves[ i ];
  45. var segmentLength = curve.getLength();
  46. var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
  47. return curve.getPointAt( u );
  48. }
  49. i ++;
  50. }
  51. return null;
  52. // loop where sum != 0, sum > d , sum+1 <d
  53. },
  54. // We cannot use the default THREE.Curve getPoint() with getLength() because in
  55. // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
  56. // getPoint() depends on getLength
  57. getLength: function () {
  58. var lens = this.getCurveLengths();
  59. return lens[ lens.length - 1 ];
  60. },
  61. // cacheLengths must be recalculated.
  62. updateArcLengths: function () {
  63. this.needsUpdate = true;
  64. this.cacheLengths = null;
  65. this.getCurveLengths();
  66. },
  67. // Compute lengths and cache them
  68. // We cannot overwrite getLengths() because UtoT mapping uses it.
  69. getCurveLengths: function () {
  70. // We use cache values if curves and cache array are same length
  71. if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
  72. return this.cacheLengths;
  73. }
  74. // Get length of sub-curve
  75. // Push sums into cached array
  76. var lengths = [], sums = 0;
  77. for ( var i = 0, l = this.curves.length; i < l; i ++ ) {
  78. sums += this.curves[ i ].getLength();
  79. lengths.push( sums );
  80. }
  81. this.cacheLengths = lengths;
  82. return lengths;
  83. },
  84. getSpacedPoints: function ( divisions ) {
  85. if ( divisions === undefined ) divisions = 40;
  86. var points = [];
  87. for ( var i = 0; i <= divisions; i ++ ) {
  88. points.push( this.getPoint( i / divisions ) );
  89. }
  90. if ( this.autoClose ) {
  91. points.push( points[ 0 ] );
  92. }
  93. return points;
  94. },
  95. getPoints: function ( divisions ) {
  96. divisions = divisions || 12;
  97. var points = [], last;
  98. for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) {
  99. var curve = curves[ i ];
  100. var resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2
  101. : ( curve && curve.isLineCurve ) ? 1
  102. : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length
  103. : divisions;
  104. var pts = curve.getPoints( resolution );
  105. for ( var j = 0; j < pts.length; j ++ ) {
  106. var point = pts[ j ];
  107. if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
  108. points.push( point );
  109. last = point;
  110. }
  111. }
  112. if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
  113. points.push( points[ 0 ] );
  114. }
  115. return points;
  116. }
  117. } );
  118. export { CurvePath };