CurvePath.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /**
  2. * @author zz85 / http://www.lab4games.net/zz85/blog
  3. *
  4. **/
  5. /**************************************************************
  6. * Curved Path - a curve path is simply a array of connected
  7. * curves, but retains the api of a curve
  8. **************************************************************/
  9. THREE.CurvePath = function () {
  10. this.curves = [];
  11. this.bends = [];
  12. this.autoClose = false; // Automatically closes the path
  13. };
  14. THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype );
  15. THREE.CurvePath.prototype.constructor = THREE.CurvePath;
  16. THREE.CurvePath.prototype.add = function ( curve ) {
  17. this.curves.push( curve );
  18. };
  19. THREE.CurvePath.prototype.checkConnection = function() {
  20. // TODO
  21. // If the ending of curve is not connected to the starting
  22. // or the next curve, then, this is not a real path
  23. };
  24. THREE.CurvePath.prototype.closePath = function() {
  25. // TODO Test
  26. // and verify for vector3 (needs to implement equals)
  27. // Add a line curve if start and end of lines are not connected
  28. var startPoint = this.curves[0].getPoint(0);
  29. var endPoint = this.curves[this.curves.length - 1].getPoint(1);
  30. if (! startPoint.equals(endPoint)) {
  31. this.curves.push( new THREE.LineCurve(endPoint, startPoint) );
  32. }
  33. };
  34. // To get accurate point with reference to
  35. // entire path distance at time t,
  36. // following has to be done:
  37. // 1. Length of each sub path have to be known
  38. // 2. Locate and identify type of curve
  39. // 3. Get t for the curve
  40. // 4. Return curve.getPointAt(t')
  41. THREE.CurvePath.prototype.getPoint = function( t ) {
  42. var d = t * this.getLength();
  43. var curveLengths = this.getCurveLengths();
  44. var i = 0, diff, curve;
  45. // To think about boundaries points.
  46. while ( i < curveLengths.length ) {
  47. if ( curveLengths[ i ] >= d ) {
  48. diff = curveLengths[ i ] - d;
  49. curve = this.curves[ i ];
  50. var u = 1 - diff / curve.getLength();
  51. return curve.getPointAt( u );
  52. }
  53. i ++;
  54. }
  55. return null;
  56. // loop where sum != 0, sum > d , sum+1 <d
  57. };
  58. /*
  59. THREE.CurvePath.prototype.getTangent = function( t ) {
  60. };*/
  61. // We cannot use the default THREE.Curve getPoint() with getLength() because in
  62. // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
  63. // getPoint() depends on getLength
  64. THREE.CurvePath.prototype.getLength = function() {
  65. var lens = this.getCurveLengths();
  66. return lens[ lens.length - 1 ];
  67. };
  68. // Compute lengths and cache them
  69. // We cannot overwrite getLengths() because UtoT mapping uses it.
  70. THREE.CurvePath.prototype.getCurveLengths = function() {
  71. // We use cache values if curves and cache array are same length
  72. if ( this.cacheLengths && this.cacheLengths.length == this.curves.length ) {
  73. return this.cacheLengths;
  74. }
  75. // Get length of subsurve
  76. // Push sums into cached array
  77. var lengths = [], sums = 0;
  78. var i, il = this.curves.length;
  79. for ( i = 0; i < il; i ++ ) {
  80. sums += this.curves[ i ].getLength();
  81. lengths.push( sums );
  82. }
  83. this.cacheLengths = lengths;
  84. return lengths;
  85. };
  86. // Returns min and max coordinates
  87. THREE.CurvePath.prototype.getBoundingBox = function () {
  88. var points = this.getPoints();
  89. var maxX, maxY, maxZ;
  90. var minX, minY, minZ;
  91. maxX = maxY = Number.NEGATIVE_INFINITY;
  92. minX = minY = Number.POSITIVE_INFINITY;
  93. var p, i, il, sum;
  94. var v3 = points[0] instanceof THREE.Vector3;
  95. sum = v3 ? new THREE.Vector3() : new THREE.Vector2();
  96. for ( i = 0, il = points.length; i < il; i ++ ) {
  97. p = points[ i ];
  98. if ( p.x > maxX ) maxX = p.x;
  99. else if ( p.x < minX ) minX = p.x;
  100. if ( p.y > maxY ) maxY = p.y;
  101. else if ( p.y < minY ) minY = p.y;
  102. if ( v3 ) {
  103. if ( p.z > maxZ ) maxZ = p.z;
  104. else if ( p.z < minZ ) minZ = p.z;
  105. }
  106. sum.add( p );
  107. }
  108. var ret = {
  109. minX: minX,
  110. minY: minY,
  111. maxX: maxX,
  112. maxY: maxY
  113. };
  114. if ( v3 ) {
  115. ret.maxZ = maxZ;
  116. ret.minZ = minZ;
  117. }
  118. return ret;
  119. };
  120. /**************************************************************
  121. * Create Geometries Helpers
  122. **************************************************************/
  123. /// Generate geometry from path points (for Line or Points objects)
  124. THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) {
  125. var pts = this.getPoints( divisions, true );
  126. return this.createGeometry( pts );
  127. };
  128. // Generate geometry from equidistance sampling along the path
  129. THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) {
  130. var pts = this.getSpacedPoints( divisions, true );
  131. return this.createGeometry( pts );
  132. };
  133. THREE.CurvePath.prototype.createGeometry = function( points ) {
  134. var geometry = new THREE.Geometry();
  135. for ( var i = 0; i < points.length; i ++ ) {
  136. geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) );
  137. }
  138. return geometry;
  139. };
  140. /**************************************************************
  141. * Bend / Wrap Helper Methods
  142. **************************************************************/
  143. // Wrap path / Bend modifiers?
  144. THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) {
  145. this.bends.push( bendpath );
  146. };
  147. THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) {
  148. var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
  149. var i, il;
  150. if ( ! bends ) {
  151. bends = this.bends;
  152. }
  153. for ( i = 0, il = bends.length; i < il; i ++ ) {
  154. oldPts = this.getWrapPoints( oldPts, bends[ i ] );
  155. }
  156. return oldPts;
  157. };
  158. THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) {
  159. var oldPts = this.getSpacedPoints( segments );
  160. var i, il;
  161. if ( ! bends ) {
  162. bends = this.bends;
  163. }
  164. for ( i = 0, il = bends.length; i < il; i ++ ) {
  165. oldPts = this.getWrapPoints( oldPts, bends[ i ] );
  166. }
  167. return oldPts;
  168. };
  169. // This returns getPoints() bend/wrapped around the contour of a path.
  170. // Read http://www.planetclegg.com/projects/WarpingTextToSplines.html
  171. THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) {
  172. var bounds = this.getBoundingBox();
  173. var i, il, p, oldX, oldY, xNorm;
  174. for ( i = 0, il = oldPts.length; i < il; i ++ ) {
  175. p = oldPts[ i ];
  176. oldX = p.x;
  177. oldY = p.y;
  178. xNorm = oldX / bounds.maxX;
  179. // If using actual distance, for length > path, requires line extrusions
  180. //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance
  181. xNorm = path.getUtoTmapping( xNorm, oldX );
  182. // check for out of bounds?
  183. var pathPt = path.getPoint( xNorm );
  184. var normal = path.getTangent( xNorm );
  185. normal.set( - normal.y, normal.x ).multiplyScalar( oldY );
  186. p.x = pathPt.x + normal.x;
  187. p.y = pathPt.y + normal.y;
  188. }
  189. return oldPts;
  190. };