Curve.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /**
  2. * @author zz85 / http://www.lab4games.net/zz85/blog
  3. * Extensible curve object
  4. *
  5. * Some common of Curve methods
  6. * .getPoint(t), getTangent(t)
  7. * .getPointAt(u), getTagentAt(u)
  8. * .getPoints(), .getSpacedPoints()
  9. * .getLength()
  10. * .updateArcLengths()
  11. *
  12. * This following classes subclasses THREE.Curve:
  13. *
  14. * -- 2d classes --
  15. * THREE.LineCurve
  16. * THREE.QuadraticBezierCurve
  17. * THREE.CubicBezierCurve
  18. * THREE.SplineCurve
  19. * THREE.ArcCurve
  20. * THREE.EllipseCurve
  21. *
  22. * -- 3d classes --
  23. * THREE.LineCurve3
  24. * THREE.QuadraticBezierCurve3
  25. * THREE.CubicBezierCurve3
  26. * THREE.SplineCurve3
  27. * THREE.ClosedSplineCurve3
  28. *
  29. * A series of curves can be represented as a THREE.CurvePath
  30. *
  31. **/
  32. /**************************************************************
  33. * Abstract Curve base class
  34. **************************************************************/
  35. THREE.Curve = function () {
  36. };
  37. // Virtual base class method to overwrite and implement in subclasses
  38. // - t [0 .. 1]
  39. THREE.Curve.prototype.getPoint = function ( t ) {
  40. console.warn( "THREE.Curve: Warning, getPoint() not implemented!" );
  41. return null;
  42. };
  43. // Get point at relative position in curve according to arc length
  44. // - u [0 .. 1]
  45. THREE.Curve.prototype.getPointAt = function ( u ) {
  46. var t = this.getUtoTmapping( u );
  47. return this.getPoint( t );
  48. };
  49. // Get sequence of points using getPoint( t )
  50. THREE.Curve.prototype.getPoints = function ( divisions ) {
  51. if ( ! divisions ) divisions = 5;
  52. var d, pts = [];
  53. for ( d = 0; d <= divisions; d ++ ) {
  54. pts.push( this.getPoint( d / divisions ) );
  55. }
  56. return pts;
  57. };
  58. // Get sequence of points using getPointAt( u )
  59. THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {
  60. if ( ! divisions ) divisions = 5;
  61. var d, pts = [];
  62. for ( d = 0; d <= divisions; d ++ ) {
  63. pts.push( this.getPointAt( d / divisions ) );
  64. }
  65. return pts;
  66. };
  67. // Get total curve arc length
  68. THREE.Curve.prototype.getLength = function () {
  69. var lengths = this.getLengths();
  70. return lengths[ lengths.length - 1 ];
  71. };
  72. // Get list of cumulative segment lengths
  73. THREE.Curve.prototype.getLengths = function ( divisions ) {
  74. if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200;
  75. if ( this.cacheArcLengths
  76. && ( this.cacheArcLengths.length === divisions + 1 )
  77. && ! this.needsUpdate) {
  78. //console.log( "cached", this.cacheArcLengths );
  79. return this.cacheArcLengths;
  80. }
  81. this.needsUpdate = false;
  82. var cache = [];
  83. var current, last = this.getPoint( 0 );
  84. var p, sum = 0;
  85. cache.push( 0 );
  86. for ( p = 1; p <= divisions; p ++ ) {
  87. current = this.getPoint ( p / divisions );
  88. sum += current.distanceTo( last );
  89. cache.push( sum );
  90. last = current;
  91. }
  92. this.cacheArcLengths = cache;
  93. return cache; // { sums: cache, sum:sum }; Sum is in the last element.
  94. };
  95. THREE.Curve.prototype.updateArcLengths = function() {
  96. this.needsUpdate = true;
  97. this.getLengths();
  98. };
  99. // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance
  100. THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
  101. var arcLengths = this.getLengths();
  102. var i = 0, il = arcLengths.length;
  103. var targetArcLength; // The targeted u distance value to get
  104. if ( distance ) {
  105. targetArcLength = distance;
  106. } else {
  107. targetArcLength = u * arcLengths[ il - 1 ];
  108. }
  109. //var time = Date.now();
  110. // binary search for the index with largest value smaller than target u distance
  111. var low = 0, high = il - 1, comparison;
  112. while ( low <= high ) {
  113. i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
  114. comparison = arcLengths[ i ] - targetArcLength;
  115. if ( comparison < 0 ) {
  116. low = i + 1;
  117. } else if ( comparison > 0 ) {
  118. high = i - 1;
  119. } else {
  120. high = i;
  121. break;
  122. // DONE
  123. }
  124. }
  125. i = high;
  126. //console.log('b' , i, low, high, Date.now()- time);
  127. if ( arcLengths[ i ] === targetArcLength ) {
  128. var t = i / ( il - 1 );
  129. return t;
  130. }
  131. // we could get finer grain at lengths, or use simple interpolatation between two points
  132. var lengthBefore = arcLengths[ i ];
  133. var lengthAfter = arcLengths[ i + 1 ];
  134. var segmentLength = lengthAfter - lengthBefore;
  135. // determine where we are between the 'before' and 'after' points
  136. var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
  137. // add that fractional amount to t
  138. var t = ( i + segmentFraction ) / ( il - 1 );
  139. return t;
  140. };
  141. // Returns a unit vector tangent at t
  142. // In case any sub curve does not implement its tangent derivation,
  143. // 2 points a small delta apart will be used to find its gradient
  144. // which seems to give a reasonable approximation
  145. THREE.Curve.prototype.getTangent = function( t ) {
  146. var delta = 0.0001;
  147. var t1 = t - delta;
  148. var t2 = t + delta;
  149. // Capping in case of danger
  150. if ( t1 < 0 ) t1 = 0;
  151. if ( t2 > 1 ) t2 = 1;
  152. var pt1 = this.getPoint( t1 );
  153. var pt2 = this.getPoint( t2 );
  154. var vec = pt2.clone().sub(pt1);
  155. return vec.normalize();
  156. };
  157. THREE.Curve.prototype.getTangentAt = function ( u ) {
  158. var t = this.getUtoTmapping( u );
  159. return this.getTangent( t );
  160. };
  161. /**************************************************************
  162. * Utils
  163. **************************************************************/
  164. THREE.Curve.Utils = {
  165. tangentQuadraticBezier: function ( t, p0, p1, p2 ) {
  166. return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );
  167. },
  168. // Puay Bing, thanks for helping with this derivative!
  169. tangentCubicBezier: function (t, p0, p1, p2, p3 ) {
  170. return - 3 * p0 * (1 - t) * (1 - t) +
  171. 3 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) +
  172. 6 * t * p2 * (1 - t) - 3 * t * t * p2 +
  173. 3 * t * t * p3;
  174. },
  175. tangentSpline: function ( t, p0, p1, p2, p3 ) {
  176. // To check if my formulas are correct
  177. var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1
  178. var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t
  179. var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2
  180. var h11 = 3 * t * t - 2 * t; // t3 − t2
  181. return h00 + h10 + h01 + h11;
  182. },
  183. // Catmull-Rom
  184. interpolate: function( p0, p1, p2, p3, t ) {
  185. var v0 = ( p2 - p0 ) * 0.5;
  186. var v1 = ( p3 - p1 ) * 0.5;
  187. var t2 = t * t;
  188. var t3 = t * t2;
  189. return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
  190. }
  191. };
  192. // TODO: Transformation for Curves?
  193. /**************************************************************
  194. * 3D Curves
  195. **************************************************************/
  196. // A Factory method for creating new curve subclasses
  197. THREE.Curve.create = function ( constructor, getPointFunc ) {
  198. constructor.prototype = Object.create( THREE.Curve.prototype );
  199. constructor.prototype.constructor = constructor;
  200. constructor.prototype.getPoint = getPointFunc;
  201. return constructor;
  202. };
粤ICP备19079148号