CurveExtras.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. import {
  2. Curve,
  3. Vector3
  4. } from 'three';
  5. /**
  6. * A bunch of parametric curves
  7. *
  8. * Formulas collected from various sources
  9. * http://mathworld.wolfram.com/HeartCurve.html
  10. * http://en.wikipedia.org/wiki/Viviani%27s_curve
  11. * http://www.mi.sanu.ac.rs/vismath/taylorapril2011/Taylor.pdf
  12. * https://prideout.net/blog/old/blog/index.html@p=44.html
  13. */
  14. /**
  15. * A Granny Knot curve.
  16. *
  17. * @augments Curve
  18. * @three_import import { GrannyKnot } from 'three/addons/curves/CurveExtras.js';
  19. */
  20. class GrannyKnot extends Curve {
  21. /**
  22. * This method returns a vector in 3D space for the given interpolation factor.
  23. *
  24. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  25. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  26. * @return {Vector3} The position on the curve.
  27. */
  28. getPoint( t, optionalTarget = new Vector3() ) {
  29. const point = optionalTarget;
  30. t = 2 * Math.PI * t;
  31. const x = - 0.22 * Math.cos( t ) - 1.28 * Math.sin( t ) - 0.44 * Math.cos( 3 * t ) - 0.78 * Math.sin( 3 * t );
  32. const y = - 0.1 * Math.cos( 2 * t ) - 0.27 * Math.sin( 2 * t ) + 0.38 * Math.cos( 4 * t ) + 0.46 * Math.sin( 4 * t );
  33. const z = 0.7 * Math.cos( 3 * t ) - 0.4 * Math.sin( 3 * t );
  34. return point.set( x, y, z ).multiplyScalar( 20 );
  35. }
  36. }
  37. /**
  38. * A heart curve.
  39. *
  40. * @augments Curve
  41. * @three_import import { HeartCurve } from 'three/addons/curves/CurveExtras.js';
  42. */
  43. class HeartCurve extends Curve {
  44. /**
  45. * Constructs a new heart curve.
  46. *
  47. * @param {number} [scale=5] - The curve's scale.
  48. */
  49. constructor( scale = 5 ) {
  50. super();
  51. /**
  52. * The curve's scale.
  53. *
  54. * @type {number}
  55. * @default 5
  56. */
  57. this.scale = scale;
  58. }
  59. /**
  60. * This method returns a vector in 3D space for the given interpolation factor.
  61. *
  62. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  63. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  64. * @return {Vector3} The position on the curve.
  65. */
  66. getPoint( t, optionalTarget = new Vector3() ) {
  67. const point = optionalTarget;
  68. t *= 2 * Math.PI;
  69. const x = 16 * Math.pow( Math.sin( t ), 3 );
  70. const y = 13 * Math.cos( t ) - 5 * Math.cos( 2 * t ) - 2 * Math.cos( 3 * t ) - Math.cos( 4 * t );
  71. const z = 0;
  72. return point.set( x, y, z ).multiplyScalar( this.scale );
  73. }
  74. }
  75. /**
  76. * A Viviani curve.
  77. *
  78. * @augments Curve
  79. * @three_import import { VivianiCurve } from 'three/addons/curves/CurveExtras.js';
  80. */
  81. class VivianiCurve extends Curve {
  82. /**
  83. * Constructs a new Viviani curve.
  84. *
  85. * @param {number} [scale=70] - The curve's scale.
  86. */
  87. constructor( scale = 70 ) {
  88. super();
  89. /**
  90. * The curve's scale.
  91. *
  92. * @type {number}
  93. * @default 70
  94. */
  95. this.scale = scale;
  96. }
  97. /**
  98. * This method returns a vector in 3D space for the given interpolation factor.
  99. *
  100. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  101. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  102. * @return {Vector3} The position on the curve.
  103. */
  104. getPoint( t, optionalTarget = new Vector3() ) {
  105. const point = optionalTarget;
  106. t = t * 4 * Math.PI; // normalized to 0..1
  107. const a = this.scale / 2;
  108. const x = a * ( 1 + Math.cos( t ) );
  109. const y = a * Math.sin( t );
  110. const z = 2 * a * Math.sin( t / 2 );
  111. return point.set( x, y, z );
  112. }
  113. }
  114. /**
  115. * A knot curve.
  116. *
  117. * @augments Curve
  118. * @three_import import { KnotCurve } from 'three/addons/curves/CurveExtras.js';
  119. */
  120. class KnotCurve extends Curve {
  121. /**
  122. * This method returns a vector in 3D space for the given interpolation factor.
  123. *
  124. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  125. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  126. * @return {Vector3} The position on the curve.
  127. */
  128. getPoint( t, optionalTarget = new Vector3() ) {
  129. const point = optionalTarget;
  130. t *= 2 * Math.PI;
  131. const R = 10;
  132. const s = 50;
  133. const x = s * Math.sin( t );
  134. const y = Math.cos( t ) * ( R + s * Math.cos( t ) );
  135. const z = Math.sin( t ) * ( R + s * Math.cos( t ) );
  136. return point.set( x, y, z );
  137. }
  138. }
  139. /**
  140. * A helix curve.
  141. *
  142. * @augments Curve
  143. * @three_import import { HelixCurve } from 'three/addons/curves/CurveExtras.js';
  144. */
  145. class HelixCurve extends Curve {
  146. /**
  147. * This method returns a vector in 3D space for the given interpolation factor.
  148. *
  149. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  150. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  151. * @return {Vector3} The position on the curve.
  152. */
  153. getPoint( t, optionalTarget = new Vector3() ) {
  154. const point = optionalTarget;
  155. const a = 30; // radius
  156. const b = 150; // height
  157. const t2 = 2 * Math.PI * t * b / 30;
  158. const x = Math.cos( t2 ) * a;
  159. const y = Math.sin( t2 ) * a;
  160. const z = b * t;
  161. return point.set( x, y, z );
  162. }
  163. }
  164. /**
  165. * A Trefoil Knot.
  166. *
  167. * @augments Curve
  168. * @three_import import { TrefoilKnot } from 'three/addons/curves/CurveExtras.js';
  169. */
  170. class TrefoilKnot extends Curve {
  171. /**
  172. * Constructs a new Trefoil Knot.
  173. *
  174. * @param {number} [scale=10] - The curve's scale.
  175. */
  176. constructor( scale = 10 ) {
  177. super();
  178. /**
  179. * The curve's scale.
  180. *
  181. * @type {number}
  182. * @default 10
  183. */
  184. this.scale = scale;
  185. }
  186. /**
  187. * This method returns a vector in 3D space for the given interpolation factor.
  188. *
  189. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  190. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  191. * @return {Vector3} The position on the curve.
  192. */
  193. getPoint( t, optionalTarget = new Vector3() ) {
  194. const point = optionalTarget;
  195. t *= Math.PI * 2;
  196. const x = ( 2 + Math.cos( 3 * t ) ) * Math.cos( 2 * t );
  197. const y = ( 2 + Math.cos( 3 * t ) ) * Math.sin( 2 * t );
  198. const z = Math.sin( 3 * t );
  199. return point.set( x, y, z ).multiplyScalar( this.scale );
  200. }
  201. }
  202. /**
  203. * A torus knot.
  204. *
  205. * @augments Curve
  206. * @three_import import { TorusKnot } from 'three/addons/curves/CurveExtras.js';
  207. */
  208. class TorusKnot extends Curve {
  209. /**
  210. * Constructs a new torus knot.
  211. *
  212. * @param {number} [scale=10] - The curve's scale.
  213. */
  214. constructor( scale = 10 ) {
  215. super();
  216. /**
  217. * The curve's scale.
  218. *
  219. * @type {number}
  220. * @default 10
  221. */
  222. this.scale = scale;
  223. }
  224. /**
  225. * This method returns a vector in 3D space for the given interpolation factor.
  226. *
  227. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  228. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  229. * @return {Vector3} The position on the curve.
  230. */
  231. getPoint( t, optionalTarget = new Vector3() ) {
  232. const point = optionalTarget;
  233. const p = 3;
  234. const q = 4;
  235. t *= Math.PI * 2;
  236. const x = ( 2 + Math.cos( q * t ) ) * Math.cos( p * t );
  237. const y = ( 2 + Math.cos( q * t ) ) * Math.sin( p * t );
  238. const z = Math.sin( q * t );
  239. return point.set( x, y, z ).multiplyScalar( this.scale );
  240. }
  241. }
  242. /**
  243. * A Cinquefoil Knot.
  244. *
  245. * @augments Curve
  246. * @three_import import { CinquefoilKnot } from 'three/addons/curves/CurveExtras.js';
  247. */
  248. class CinquefoilKnot extends Curve {
  249. /**
  250. * Constructs a new Cinquefoil Knot.
  251. *
  252. * @param {number} [scale=10] - The curve's scale.
  253. */
  254. constructor( scale = 10 ) {
  255. super();
  256. /**
  257. * The curve's scale.
  258. *
  259. * @type {number}
  260. * @default 10
  261. */
  262. this.scale = scale;
  263. }
  264. /**
  265. * This method returns a vector in 3D space for the given interpolation factor.
  266. *
  267. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  268. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  269. * @return {Vector3} The position on the curve.
  270. */
  271. getPoint( t, optionalTarget = new Vector3() ) {
  272. const point = optionalTarget;
  273. const p = 2;
  274. const q = 5;
  275. t *= Math.PI * 2;
  276. const x = ( 2 + Math.cos( q * t ) ) * Math.cos( p * t );
  277. const y = ( 2 + Math.cos( q * t ) ) * Math.sin( p * t );
  278. const z = Math.sin( q * t );
  279. return point.set( x, y, z ).multiplyScalar( this.scale );
  280. }
  281. }
  282. /**
  283. * A Trefoil Polynomial Knot.
  284. *
  285. * @augments Curve
  286. * @three_import import { TrefoilPolynomialKnot } from 'three/addons/curves/CurveExtras.js';
  287. */
  288. class TrefoilPolynomialKnot extends Curve {
  289. /**
  290. * Constructs a new Trefoil Polynomial Knot.
  291. *
  292. * @param {number} [scale=10] - The curve's scale.
  293. */
  294. constructor( scale = 10 ) {
  295. super();
  296. /**
  297. * The curve's scale.
  298. *
  299. * @type {number}
  300. * @default 10
  301. */
  302. this.scale = scale;
  303. }
  304. /**
  305. * This method returns a vector in 3D space for the given interpolation factor.
  306. *
  307. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  308. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  309. * @return {Vector3} The position on the curve.
  310. */
  311. getPoint( t, optionalTarget = new Vector3() ) {
  312. const point = optionalTarget;
  313. t = t * 4 - 2;
  314. const x = Math.pow( t, 3 ) - 3 * t;
  315. const y = Math.pow( t, 4 ) - 4 * t * t;
  316. const z = 1 / 5 * Math.pow( t, 5 ) - 2 * t;
  317. return point.set( x, y, z ).multiplyScalar( this.scale );
  318. }
  319. }
  320. function scaleTo( x, y, t ) {
  321. const r = y - x;
  322. return t * r + x;
  323. }
  324. /**
  325. * A Figure Eight Polynomial Knot.
  326. *
  327. * @augments Curve
  328. * @three_import import { FigureEightPolynomialKnot } from 'three/addons/curves/CurveExtras.js';
  329. */
  330. class FigureEightPolynomialKnot extends Curve {
  331. /**
  332. * Constructs a new Figure Eight Polynomial Knot.
  333. *
  334. * @param {number} [scale=1] - The curve's scale.
  335. */
  336. constructor( scale = 1 ) {
  337. super();
  338. /**
  339. * The curve's scale.
  340. *
  341. * @type {number}
  342. * @default 1
  343. */
  344. this.scale = scale;
  345. }
  346. /**
  347. * This method returns a vector in 3D space for the given interpolation factor.
  348. *
  349. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  350. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  351. * @return {Vector3} The position on the curve.
  352. */
  353. getPoint( t, optionalTarget = new Vector3() ) {
  354. const point = optionalTarget;
  355. t = scaleTo( - 4, 4, t );
  356. const x = 2 / 5 * t * ( t * t - 7 ) * ( t * t - 10 );
  357. const y = Math.pow( t, 4 ) - 13 * t * t;
  358. const z = 1 / 10 * t * ( t * t - 4 ) * ( t * t - 9 ) * ( t * t - 12 );
  359. return point.set( x, y, z ).multiplyScalar( this.scale );
  360. }
  361. }
  362. /**
  363. * A Decorated Torus Knot 4a.
  364. *
  365. * @augments Curve
  366. * @three_import import { DecoratedTorusKnot4a } from 'three/addons/curves/CurveExtras.js';
  367. */
  368. class DecoratedTorusKnot4a extends Curve {
  369. /**
  370. * Constructs a new Decorated Torus Knot 4a.
  371. *
  372. * @param {number} [scale=1] - The curve's scale.
  373. */
  374. constructor( scale = 40 ) {
  375. super();
  376. /**
  377. * The curve's scale.
  378. *
  379. * @type {number}
  380. * @default 40
  381. */
  382. this.scale = scale;
  383. }
  384. /**
  385. * This method returns a vector in 3D space for the given interpolation factor.
  386. *
  387. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  388. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  389. * @return {Vector3} The position on the curve.
  390. */
  391. getPoint( t, optionalTarget = new Vector3() ) {
  392. const point = optionalTarget;
  393. t *= Math.PI * 2;
  394. const x = Math.cos( 2 * t ) * ( 1 + 0.6 * ( Math.cos( 5 * t ) + 0.75 * Math.cos( 10 * t ) ) );
  395. const y = Math.sin( 2 * t ) * ( 1 + 0.6 * ( Math.cos( 5 * t ) + 0.75 * Math.cos( 10 * t ) ) );
  396. const z = 0.35 * Math.sin( 5 * t );
  397. return point.set( x, y, z ).multiplyScalar( this.scale );
  398. }
  399. }
  400. /**
  401. * A Decorated Torus Knot 4b.
  402. *
  403. * @augments Curve
  404. * @three_import import { DecoratedTorusKnot4b } from 'three/addons/curves/CurveExtras.js';
  405. */
  406. class DecoratedTorusKnot4b extends Curve {
  407. /**
  408. * Constructs a new Decorated Torus Knot 4b.
  409. *
  410. * @param {number} [scale=1] - The curve's scale.
  411. */
  412. constructor( scale = 40 ) {
  413. super();
  414. /**
  415. * The curve's scale.
  416. *
  417. * @type {number}
  418. * @default 40
  419. */
  420. this.scale = scale;
  421. }
  422. /**
  423. * This method returns a vector in 3D space for the given interpolation factor.
  424. *
  425. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  426. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  427. * @return {Vector3} The position on the curve.
  428. */
  429. getPoint( t, optionalTarget = new Vector3() ) {
  430. const point = optionalTarget;
  431. const fi = t * Math.PI * 2;
  432. const x = Math.cos( 2 * fi ) * ( 1 + 0.45 * Math.cos( 3 * fi ) + 0.4 * Math.cos( 9 * fi ) );
  433. const y = Math.sin( 2 * fi ) * ( 1 + 0.45 * Math.cos( 3 * fi ) + 0.4 * Math.cos( 9 * fi ) );
  434. const z = 0.2 * Math.sin( 9 * fi );
  435. return point.set( x, y, z ).multiplyScalar( this.scale );
  436. }
  437. }
  438. /**
  439. * A Decorated Torus Knot 5a.
  440. *
  441. * @augments Curve
  442. * @three_import import { DecoratedTorusKnot5a } from 'three/addons/curves/CurveExtras.js';
  443. */
  444. class DecoratedTorusKnot5a extends Curve {
  445. /**
  446. * Constructs a new Decorated Torus Knot 5a.
  447. *
  448. * @param {number} [scale=1] - The curve's scale.
  449. */
  450. constructor( scale = 40 ) {
  451. super();
  452. /**
  453. * The curve's scale.
  454. *
  455. * @type {number}
  456. * @default 40
  457. */
  458. this.scale = scale;
  459. }
  460. /**
  461. * This method returns a vector in 3D space for the given interpolation factor.
  462. *
  463. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  464. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  465. * @return {Vector3} The position on the curve.
  466. */
  467. getPoint( t, optionalTarget = new Vector3() ) {
  468. const point = optionalTarget;
  469. const fi = t * Math.PI * 2;
  470. const x = Math.cos( 3 * fi ) * ( 1 + 0.3 * Math.cos( 5 * fi ) + 0.5 * Math.cos( 10 * fi ) );
  471. const y = Math.sin( 3 * fi ) * ( 1 + 0.3 * Math.cos( 5 * fi ) + 0.5 * Math.cos( 10 * fi ) );
  472. const z = 0.2 * Math.sin( 20 * fi );
  473. return point.set( x, y, z ).multiplyScalar( this.scale );
  474. }
  475. }
  476. /**
  477. * A Decorated Torus Knot 5c.
  478. *
  479. * @augments Curve
  480. * @three_import import { DecoratedTorusKnot5c } from 'three/addons/curves/CurveExtras.js';
  481. */
  482. class DecoratedTorusKnot5c extends Curve {
  483. /**
  484. * Constructs a new Decorated Torus Knot 5c.
  485. *
  486. * @param {number} [scale=1] - The curve's scale.
  487. */
  488. constructor( scale = 40 ) {
  489. super();
  490. /**
  491. * The curve's scale.
  492. *
  493. * @type {number}
  494. * @default 40
  495. */
  496. this.scale = scale;
  497. }
  498. /**
  499. * This method returns a vector in 3D space for the given interpolation factor.
  500. *
  501. * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`.
  502. * @param {Vector3} [optionalTarget] - The optional target vector the result is written to.
  503. * @return {Vector3} The position on the curve.
  504. */
  505. getPoint( t, optionalTarget = new Vector3() ) {
  506. const point = optionalTarget;
  507. const fi = t * Math.PI * 2;
  508. const x = Math.cos( 4 * fi ) * ( 1 + 0.5 * ( Math.cos( 5 * fi ) + 0.4 * Math.cos( 20 * fi ) ) );
  509. const y = Math.sin( 4 * fi ) * ( 1 + 0.5 * ( Math.cos( 5 * fi ) + 0.4 * Math.cos( 20 * fi ) ) );
  510. const z = 0.35 * Math.sin( 15 * fi );
  511. return point.set( x, y, z ).multiplyScalar( this.scale );
  512. }
  513. }
  514. export {
  515. GrannyKnot,
  516. HeartCurve,
  517. VivianiCurve,
  518. KnotCurve,
  519. HelixCurve,
  520. TrefoilKnot,
  521. TorusKnot,
  522. CinquefoilKnot,
  523. TrefoilPolynomialKnot,
  524. FigureEightPolynomialKnot,
  525. DecoratedTorusKnot4a,
  526. DecoratedTorusKnot4b,
  527. DecoratedTorusKnot5a,
  528. DecoratedTorusKnot5c
  529. };