/home/lindsay/xeolabs/xeogl-next/xeogl/examples/js/curves/splineCurve.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/examples/js/curves/splineCurve.js

  1. /**
  2. A **SplineCurve** is a {{#crossLink "Curve"}}{{/crossLink}} along which a 3D position can be animated.
  3.  
  4. ## Overview
  5.  
  6. <ul>
  7. <li>As shown in the diagram below, a SplineCurve is defined by three or more control points.</li>
  8. <li>You can sample a {{#crossLink "SplineCurve/point:property"}}{{/crossLink}} and a {{#crossLink "Curve/tangent:property"}}{{/crossLink}}
  9. vector on a SplineCurve for any given value of {{#crossLink "SplineCurve/t:property"}}{{/crossLink}} in the range [0..1].</li>
  10. <li>When you set {{#crossLink "SplineCurve/t:property"}}{{/crossLink}} on a SplineCurve, its {{#crossLink "SplineCurve/point:property"}}{{/crossLink}} and {{#crossLink "Curve/tangent:property"}}{{/crossLink}} properties will update accordingly.</li>
  11. <li>To build a complex path, you can combine an unlimited combination of SplineCurves,
  12. {{#crossLink "CubicBezierCurve"}}CubicBezierCurves{{/crossLink}} and {{#crossLink "QuadraticBezierCurve"}}QuadraticBezierCurves{{/crossLink}}
  13. into a {{#crossLink "Path"}}{{/crossLink}}.</li>
  14. </ul>
  15.  
  16. <img style="border:1px solid; background: white;" src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/72/Quadratic_spline_six_segments.svg/200px-Quadratic_spline_six_segments.svg.png"/><br>
  17. *<a href="https://en.wikipedia.org/wiki/Spline_(mathematics)">Spline Curve from Wikipedia</a>*
  18.  
  19. ## Examples
  20.  
  21. <ul>
  22. <li>[Simple SplineCurve example](../../examples/#animation_curves_spline)</li>
  23. <li>[Moving a PointLight along a SplineCurve](../../examples/#animation_curves_spline_pointLight)</li>
  24. <li>[Path example](../../examples/#animation_curves_path)</li>
  25. </ul>
  26.  
  27. ## Usage
  28.  
  29. #### Animation along a SplineCurve
  30.  
  31. Let's create a SplineCurve, subscribe to updates on its {{#crossLink "SplineCurve/point:property"}}{{/crossLink}},
  32. {{#crossLink "Curve/tangent:property"}}{{/crossLink}} and {{#crossLink "Curve/t:property"}}{{/crossLink}} properties,
  33. then vary its {{#crossLink "SplineCurve/t:property"}}{{/crossLink}}
  34. property over time:
  35.  
  36. ````javascript
  37. var curve = new xeogl.SplineCurve({
  38. points: [
  39. [-10, 0, 0],
  40. [-5, 15, 0],
  41. [20, 15, 0],
  42. [10, 0, 0]
  43. ]
  44. });
  45.  
  46. curve.on("point", function(point) {
  47. this.log("curve.point=" + JSON.stringify(point));
  48. });
  49.  
  50. curve.on("tangent", function(tangent) {
  51. this.log("curve.tangent=" + JSON.stringify(tangent));
  52. });
  53.  
  54. curve.on("t", function(t) {
  55. this.log("curve.t=" + t);
  56. });
  57.  
  58. curve.scene.on("tick", function(e) {
  59. curve.t = (e.time - e.startTime) * 0.01;
  60. });
  61. ````
  62.  
  63. #### Randomly sampling points
  64.  
  65. Use SplineCurve's {{#crossLink "SplineCurve/getPoint:method"}}{{/crossLink}} and
  66. {{#crossLink "Curve/getTangent:method"}}{{/crossLink}} methods to sample the point and vector
  67. at a given **t**:
  68.  
  69. ````javascript
  70. curve.scene.on("tick", function(e) {
  71.  
  72. var t = (e.time - e.startTime) * 0.01;
  73.  
  74. var point = curve.getPoint(t);
  75. var tangent = curve.getTangent(t);
  76.  
  77. this.log("t=" + t + ", point=" + JSON.stringify(point) + ", tangent=" + JSON.stringify(tangent));
  78. });
  79. ````
  80.  
  81. #### Sampling multiple points
  82.  
  83. Use SplineCurve's {{#crossLink "Curve/getPoints:method"}}{{/crossLink}} method to sample a list of equidistant points
  84. along it. In the snippet below, we'll build a {{#crossLink "Geometry"}}{{/crossLink}} that renders a line along the
  85. curve. Note that we need to flatten the points array for consumption by the {{#crossLink "Geometry"}}{{/crossLink}}.
  86.  
  87. ````javascript
  88. var geometry = new xeogl.Geometry({
  89. positions: xeogl.math.flatten(curve.getPoints(50))
  90. });
  91. ````
  92.  
  93. @class SplineCurve
  94. @module xeogl
  95. @submodule curves
  96. @constructor
  97. @param [scene] {Scene} Parent {{#crossLink "Scene"}}Scene{{/crossLink}}.
  98. @param [cfg] {*} Configuration
  99. @param [cfg.id] {String} Optional ID, unique among all components in the parent {{#crossLink "Scene"}}Scene{{/crossLink}}, generated automatically when omitted.
  100. @param [cfg.meta] {String:Object} Optional map of user-defined metadata to attach to this SplineCurve.
  101. @param [cfg.points=[]] Control points on this SplineCurve.
  102. @param [cfg.t=0] Current position on this SplineCurve, in range between 0..1.
  103. @extends Curve
  104. */
  105. xeogl.SplineCurve = class xeoglSplineCurve extends xeogl.Curve {
  106.  
  107. init(cfg) {
  108. super.init(cfg);
  109. this.points = cfg.points;
  110. this.t = cfg.t;
  111. }
  112.  
  113. /**
  114. Control points on this SplineCurve.
  115.  
  116. Fires a {{#crossLink "SplineCurve/points:event"}}{{/crossLink}} event on change.
  117.  
  118. @property points
  119. @default []
  120. @type Float32Array
  121. */
  122. set points(value) {
  123. this._points = value || [];
  124. /**
  125. * Fired whenever this SplineCurve's
  126. * {{#crossLink "SplineCurve/points:property"}}{{/crossLink}} property changes.
  127. * @event points
  128. * @param value The property's new value
  129. */
  130. this.fire("points", this._points);
  131. }
  132.  
  133. get points() {
  134. return this._points;
  135. }
  136.  
  137. /**
  138. Progress along this SplineCurve.
  139.  
  140. Automatically clamps to range [0..1].
  141.  
  142. Fires a {{#crossLink "SplineCurve/t:event"}}{{/crossLink}} event on change.
  143.  
  144. @property t
  145. @default 0
  146. @type Number
  147. */
  148. set t(value) {
  149. value = value || 0;
  150. this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value);
  151. /**
  152. * Fired whenever this SplineCurve's
  153. * {{#crossLink "SplineCurve/t:property"}}{{/crossLink}} property changes.
  154. * @event t
  155. * @param value The property's new value
  156. */
  157. this.fire("t", this._t);
  158. }
  159.  
  160. get t() {
  161. return this._t;
  162. }
  163.  
  164. /**
  165. Point on this SplineCurve at position {{#crossLink "SplineCurve/t:property"}}{{/crossLink}}.
  166.  
  167. @property point
  168. @type {{Array of Number}}
  169. */
  170. get point() {
  171. return this.getPoint(this._t);
  172. }
  173.  
  174. /**
  175. * Returns point on this SplineCurve at the given position.
  176. * @method getPoint
  177. * @param {Number} t Position to get point at.
  178. * @returns {{Array of Number}}
  179. */
  180. getPoint(t) {
  181.  
  182. var math = xeogl.math;
  183.  
  184. var points = this.points;
  185.  
  186. if (points.length < 3) {
  187. this.error("Can't sample point from SplineCurve - not enough points on curve - returning [0,0,0].");
  188. return;
  189. }
  190.  
  191. var point = ( points.length - 1 ) * t;
  192.  
  193. var intPoint = Math.floor(point);
  194. var weight = point - intPoint;
  195.  
  196. var point0 = points[intPoint === 0 ? intPoint : intPoint - 1];
  197. var point1 = points[intPoint];
  198. var point2 = points[intPoint > points.length - 2 ? points.length - 1 : intPoint + 1];
  199. var point3 = points[intPoint > points.length - 3 ? points.length - 1 : intPoint + 2];
  200.  
  201. var vector = math.vec3();
  202.  
  203. vector[0] = math.catmullRomInterpolate(point0[0], point1[0], point2[0], point3[0], weight);
  204. vector[1] = math.catmullRomInterpolate(point0[1], point1[1], point2[1], point3[1], weight);
  205. vector[2] = math.catmullRomInterpolate(point0[2], point1[2], point2[2], point3[2], weight);
  206.  
  207. return vector;
  208. }
  209.  
  210. getJSON() {
  211. return {
  212. points: points,
  213. t: this._t
  214. };
  215. }
  216. };
  217.