Spline.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import Check from "./Check.js";
  2. import defaultValue from "./defaultValue.js";
  3. import defined from "./defined.js";
  4. import DeveloperError from "./DeveloperError.js";
  5. import CesiumMath from "./Math.js";
  6. /**
  7. * Creates a curve parameterized and evaluated by time. This type describes an interface
  8. * and is not intended to be instantiated directly.
  9. *
  10. * @alias Spline
  11. * @constructor
  12. *
  13. * @see CatmullRomSpline
  14. * @see HermiteSpline
  15. * @see LinearSpline
  16. * @see QuaternionSpline
  17. */
  18. function Spline() {
  19. /**
  20. * An array of times for the control points.
  21. * @type {Number[]}
  22. * @default undefined
  23. */
  24. this.times = undefined;
  25. /**
  26. * An array of control points.
  27. * @type {Cartesian3[]|Quaternion[]}
  28. * @default undefined
  29. */
  30. this.points = undefined;
  31. DeveloperError.throwInstantiationError();
  32. }
  33. /**
  34. * Evaluates the curve at a given time.
  35. * @function
  36. *
  37. * @param {Number} time The time at which to evaluate the curve.
  38. * @param {Cartesian3|Quaternion|Number[]} [result] The object onto which to store the result.
  39. * @returns {Cartesian3|Quaternion|Number[]} The modified result parameter or a new instance of the point on the curve at the given time.
  40. *
  41. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  42. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  43. * in the array <code>times</code>.
  44. */
  45. Spline.prototype.evaluate = DeveloperError.throwInstantiationError;
  46. /**
  47. * Finds an index <code>i</code> in <code>times</code> such that the parameter
  48. * <code>time</code> is in the interval <code>[times[i], times[i + 1]]</code>.
  49. *
  50. * @param {Number} time The time.
  51. * @param {Number} startIndex The index from which to start the search.
  52. * @returns {Number} The index for the element at the start of the interval.
  53. *
  54. * @exception {DeveloperError} time must be in the range <code>[t<sub>0</sub>, t<sub>n</sub>]</code>, where <code>t<sub>0</sub></code>
  55. * is the first element in the array <code>times</code> and <code>t<sub>n</sub></code> is the last element
  56. * in the array <code>times</code>.
  57. */
  58. Spline.prototype.findTimeInterval = function (time, startIndex) {
  59. var times = this.times;
  60. var length = times.length;
  61. //>>includeStart('debug', pragmas.debug);
  62. if (!defined(time)) {
  63. throw new DeveloperError("time is required.");
  64. }
  65. if (time < times[0] || time > times[length - 1]) {
  66. throw new DeveloperError("time is out of range.");
  67. }
  68. //>>includeEnd('debug');
  69. // Take advantage of temporal coherence by checking current, next and previous intervals
  70. // for containment of time.
  71. startIndex = defaultValue(startIndex, 0);
  72. if (time >= times[startIndex]) {
  73. if (startIndex + 1 < length && time < times[startIndex + 1]) {
  74. return startIndex;
  75. } else if (startIndex + 2 < length && time < times[startIndex + 2]) {
  76. return startIndex + 1;
  77. }
  78. } else if (startIndex - 1 >= 0 && time >= times[startIndex - 1]) {
  79. return startIndex - 1;
  80. }
  81. // The above failed so do a linear search. For the use cases so far, the
  82. // length of the list is less than 10. In the future, if there is a bottle neck,
  83. // it might be here.
  84. var i;
  85. if (time > times[startIndex]) {
  86. for (i = startIndex; i < length - 1; ++i) {
  87. if (time >= times[i] && time < times[i + 1]) {
  88. break;
  89. }
  90. }
  91. } else {
  92. for (i = startIndex - 1; i >= 0; --i) {
  93. if (time >= times[i] && time < times[i + 1]) {
  94. break;
  95. }
  96. }
  97. }
  98. if (i === length - 1) {
  99. i = length - 2;
  100. }
  101. return i;
  102. };
  103. /**
  104. * Wraps the given time to the period covered by the spline.
  105. * @function
  106. *
  107. * @param {Number} time The time.
  108. * @return {Number} The time, wrapped around the animation period.
  109. */
  110. Spline.prototype.wrapTime = function (time) {
  111. //>>includeStart('debug', pragmas.debug);
  112. Check.typeOf.number("time", time);
  113. //>>includeEnd('debug');
  114. var times = this.times;
  115. var timeEnd = times[times.length - 1];
  116. var timeStart = times[0];
  117. var timeStretch = timeEnd - timeStart;
  118. var divs;
  119. if (time < timeStart) {
  120. divs = Math.floor((timeStart - time) / timeStretch) + 1;
  121. time += divs * timeStretch;
  122. }
  123. if (time > timeEnd) {
  124. divs = Math.floor((time - timeEnd) / timeStretch) + 1;
  125. time -= divs * timeStretch;
  126. }
  127. return time;
  128. };
  129. /**
  130. * Clamps the given time to the period covered by the spline.
  131. * @function
  132. *
  133. * @param {Number} time The time.
  134. * @return {Number} The time, clamped to the animation period.
  135. */
  136. Spline.prototype.clampTime = function (time) {
  137. //>>includeStart('debug', pragmas.debug);
  138. Check.typeOf.number("time", time);
  139. //>>includeEnd('debug');
  140. var times = this.times;
  141. return CesiumMath.clamp(time, times[0], times[times.length - 1]);
  142. };
  143. export default Spline;