NURBSUtils.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /**
  2. * @author renej
  3. * NURBS utils
  4. *
  5. * See NURBSCurve and NURBSSurface.
  6. *
  7. **/
  8. import {
  9. Vector3,
  10. Vector4
  11. } from "../../../build/three.module.js";
  12. /**************************************************************
  13. * NURBS Utils
  14. **************************************************************/
  15. var NURBSUtils = {
  16. /*
  17. Finds knot vector span.
  18. p : degree
  19. u : parametric value
  20. U : knot vector
  21. returns the span
  22. */
  23. findSpan: function ( p, u, U ) {
  24. var n = U.length - p - 1;
  25. if ( u >= U[ n ] ) {
  26. return n - 1;
  27. }
  28. if ( u <= U[ p ] ) {
  29. return p;
  30. }
  31. var low = p;
  32. var high = n;
  33. var mid = Math.floor( ( low + high ) / 2 );
  34. while ( u < U[ mid ] || u >= U[ mid + 1 ] ) {
  35. if ( u < U[ mid ] ) {
  36. high = mid;
  37. } else {
  38. low = mid;
  39. }
  40. mid = Math.floor( ( low + high ) / 2 );
  41. }
  42. return mid;
  43. },
  44. /*
  45. Calculate basis functions. See The NURBS Book, page 70, algorithm A2.2
  46. span : span in which u lies
  47. u : parametric point
  48. p : degree
  49. U : knot vector
  50. returns array[p+1] with basis functions values.
  51. */
  52. calcBasisFunctions: function ( span, u, p, U ) {
  53. var N = [];
  54. var left = [];
  55. var right = [];
  56. N[ 0 ] = 1.0;
  57. for ( var j = 1; j <= p; ++ j ) {
  58. left[ j ] = u - U[ span + 1 - j ];
  59. right[ j ] = U[ span + j ] - u;
  60. var saved = 0.0;
  61. for ( var r = 0; r < j; ++ r ) {
  62. var rv = right[ r + 1 ];
  63. var lv = left[ j - r ];
  64. var temp = N[ r ] / ( rv + lv );
  65. N[ r ] = saved + rv * temp;
  66. saved = lv * temp;
  67. }
  68. N[ j ] = saved;
  69. }
  70. return N;
  71. },
  72. /*
  73. Calculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.
  74. p : degree of B-Spline
  75. U : knot vector
  76. P : control points (x, y, z, w)
  77. u : parametric point
  78. returns point for given u
  79. */
  80. calcBSplinePoint: function ( p, U, P, u ) {
  81. var span = this.findSpan( p, u, U );
  82. var N = this.calcBasisFunctions( span, u, p, U );
  83. var C = new Vector4( 0, 0, 0, 0 );
  84. for ( var j = 0; j <= p; ++ j ) {
  85. var point = P[ span - p + j ];
  86. var Nj = N[ j ];
  87. var wNj = point.w * Nj;
  88. C.x += point.x * wNj;
  89. C.y += point.y * wNj;
  90. C.z += point.z * wNj;
  91. C.w += point.w * Nj;
  92. }
  93. return C;
  94. },
  95. /*
  96. Calculate basis functions derivatives. See The NURBS Book, page 72, algorithm A2.3.
  97. span : span in which u lies
  98. u : parametric point
  99. p : degree
  100. n : number of derivatives to calculate
  101. U : knot vector
  102. returns array[n+1][p+1] with basis functions derivatives
  103. */
  104. calcBasisFunctionDerivatives: function ( span, u, p, n, U ) {
  105. var zeroArr = [];
  106. for ( var i = 0; i <= p; ++ i )
  107. zeroArr[ i ] = 0.0;
  108. var ders = [];
  109. for ( var i = 0; i <= n; ++ i )
  110. ders[ i ] = zeroArr.slice( 0 );
  111. var ndu = [];
  112. for ( var i = 0; i <= p; ++ i )
  113. ndu[ i ] = zeroArr.slice( 0 );
  114. ndu[ 0 ][ 0 ] = 1.0;
  115. var left = zeroArr.slice( 0 );
  116. var right = zeroArr.slice( 0 );
  117. for ( var j = 1; j <= p; ++ j ) {
  118. left[ j ] = u - U[ span + 1 - j ];
  119. right[ j ] = U[ span + j ] - u;
  120. var saved = 0.0;
  121. for ( var r = 0; r < j; ++ r ) {
  122. var rv = right[ r + 1 ];
  123. var lv = left[ j - r ];
  124. ndu[ j ][ r ] = rv + lv;
  125. var temp = ndu[ r ][ j - 1 ] / ndu[ j ][ r ];
  126. ndu[ r ][ j ] = saved + rv * temp;
  127. saved = lv * temp;
  128. }
  129. ndu[ j ][ j ] = saved;
  130. }
  131. for ( var j = 0; j <= p; ++ j ) {
  132. ders[ 0 ][ j ] = ndu[ j ][ p ];
  133. }
  134. for ( var r = 0; r <= p; ++ r ) {
  135. var s1 = 0;
  136. var s2 = 1;
  137. var a = [];
  138. for ( var i = 0; i <= p; ++ i ) {
  139. a[ i ] = zeroArr.slice( 0 );
  140. }
  141. a[ 0 ][ 0 ] = 1.0;
  142. for ( var k = 1; k <= n; ++ k ) {
  143. var d = 0.0;
  144. var rk = r - k;
  145. var pk = p - k;
  146. if ( r >= k ) {
  147. a[ s2 ][ 0 ] = a[ s1 ][ 0 ] / ndu[ pk + 1 ][ rk ];
  148. d = a[ s2 ][ 0 ] * ndu[ rk ][ pk ];
  149. }
  150. var j1 = ( rk >= - 1 ) ? 1 : - rk;
  151. var j2 = ( r - 1 <= pk ) ? k - 1 : p - r;
  152. for ( var j = j1; j <= j2; ++ j ) {
  153. a[ s2 ][ j ] = ( a[ s1 ][ j ] - a[ s1 ][ j - 1 ] ) / ndu[ pk + 1 ][ rk + j ];
  154. d += a[ s2 ][ j ] * ndu[ rk + j ][ pk ];
  155. }
  156. if ( r <= pk ) {
  157. a[ s2 ][ k ] = - a[ s1 ][ k - 1 ] / ndu[ pk + 1 ][ r ];
  158. d += a[ s2 ][ k ] * ndu[ r ][ pk ];
  159. }
  160. ders[ k ][ r ] = d;
  161. var j = s1;
  162. s1 = s2;
  163. s2 = j;
  164. }
  165. }
  166. var r = p;
  167. for ( var k = 1; k <= n; ++ k ) {
  168. for ( var j = 0; j <= p; ++ j ) {
  169. ders[ k ][ j ] *= r;
  170. }
  171. r *= p - k;
  172. }
  173. return ders;
  174. },
  175. /*
  176. Calculate derivatives of a B-Spline. See The NURBS Book, page 93, algorithm A3.2.
  177. p : degree
  178. U : knot vector
  179. P : control points
  180. u : Parametric points
  181. nd : number of derivatives
  182. returns array[d+1] with derivatives
  183. */
  184. calcBSplineDerivatives: function ( p, U, P, u, nd ) {
  185. var du = nd < p ? nd : p;
  186. var CK = [];
  187. var span = this.findSpan( p, u, U );
  188. var nders = this.calcBasisFunctionDerivatives( span, u, p, du, U );
  189. var Pw = [];
  190. for ( var i = 0; i < P.length; ++ i ) {
  191. var point = P[ i ].clone();
  192. var w = point.w;
  193. point.x *= w;
  194. point.y *= w;
  195. point.z *= w;
  196. Pw[ i ] = point;
  197. }
  198. for ( var k = 0; k <= du; ++ k ) {
  199. var point = Pw[ span - p ].clone().multiplyScalar( nders[ k ][ 0 ] );
  200. for ( var j = 1; j <= p; ++ j ) {
  201. point.add( Pw[ span - p + j ].clone().multiplyScalar( nders[ k ][ j ] ) );
  202. }
  203. CK[ k ] = point;
  204. }
  205. for ( var k = du + 1; k <= nd + 1; ++ k ) {
  206. CK[ k ] = new Vector4( 0, 0, 0 );
  207. }
  208. return CK;
  209. },
  210. /*
  211. Calculate "K over I"
  212. returns k!/(i!(k-i)!)
  213. */
  214. calcKoverI: function ( k, i ) {
  215. var nom = 1;
  216. for ( var j = 2; j <= k; ++ j ) {
  217. nom *= j;
  218. }
  219. var denom = 1;
  220. for ( var j = 2; j <= i; ++ j ) {
  221. denom *= j;
  222. }
  223. for ( var j = 2; j <= k - i; ++ j ) {
  224. denom *= j;
  225. }
  226. return nom / denom;
  227. },
  228. /*
  229. Calculate derivatives (0-nd) of rational curve. See The NURBS Book, page 127, algorithm A4.2.
  230. Pders : result of function calcBSplineDerivatives
  231. returns array with derivatives for rational curve.
  232. */
  233. calcRationalCurveDerivatives: function ( Pders ) {
  234. var nd = Pders.length;
  235. var Aders = [];
  236. var wders = [];
  237. for ( var i = 0; i < nd; ++ i ) {
  238. var point = Pders[ i ];
  239. Aders[ i ] = new Vector3( point.x, point.y, point.z );
  240. wders[ i ] = point.w;
  241. }
  242. var CK = [];
  243. for ( var k = 0; k < nd; ++ k ) {
  244. var v = Aders[ k ].clone();
  245. for ( var i = 1; i <= k; ++ i ) {
  246. v.sub( CK[ k - i ].clone().multiplyScalar( this.calcKoverI( k, i ) * wders[ i ] ) );
  247. }
  248. CK[ k ] = v.divideScalar( wders[ 0 ] );
  249. }
  250. return CK;
  251. },
  252. /*
  253. Calculate NURBS curve derivatives. See The NURBS Book, page 127, algorithm A4.2.
  254. p : degree
  255. U : knot vector
  256. P : control points in homogeneous space
  257. u : parametric points
  258. nd : number of derivatives
  259. returns array with derivatives.
  260. */
  261. calcNURBSDerivatives: function ( p, U, P, u, nd ) {
  262. var Pders = this.calcBSplineDerivatives( p, U, P, u, nd );
  263. return this.calcRationalCurveDerivatives( Pders );
  264. },
  265. /*
  266. Calculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.
  267. p1, p2 : degrees of B-Spline surface
  268. U1, U2 : knot vectors
  269. P : control points (x, y, z, w)
  270. u, v : parametric values
  271. returns point for given (u, v)
  272. */
  273. calcSurfacePoint: function ( p, q, U, V, P, u, v, target ) {
  274. var uspan = this.findSpan( p, u, U );
  275. var vspan = this.findSpan( q, v, V );
  276. var Nu = this.calcBasisFunctions( uspan, u, p, U );
  277. var Nv = this.calcBasisFunctions( vspan, v, q, V );
  278. var temp = [];
  279. for ( var l = 0; l <= q; ++ l ) {
  280. temp[ l ] = new Vector4( 0, 0, 0, 0 );
  281. for ( var k = 0; k <= p; ++ k ) {
  282. var point = P[ uspan - p + k ][ vspan - q + l ].clone();
  283. var w = point.w;
  284. point.x *= w;
  285. point.y *= w;
  286. point.z *= w;
  287. temp[ l ].add( point.multiplyScalar( Nu[ k ] ) );
  288. }
  289. }
  290. var Sw = new Vector4( 0, 0, 0, 0 );
  291. for ( var l = 0; l <= q; ++ l ) {
  292. Sw.add( temp[ l ].multiplyScalar( Nv[ l ] ) );
  293. }
  294. Sw.divideScalar( Sw.w );
  295. target.set( Sw.x, Sw.y, Sw.z );
  296. }
  297. };
  298. export { NURBSUtils };