HermitePolynomialApproximation.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import defaultValue from './defaultValue.js';
  2. import defined from './defined.js';
  3. import DeveloperError from './DeveloperError.js';
  4. import CesiumMath from './Math.js';
  5. var factorial = CesiumMath.factorial;
  6. function calculateCoefficientTerm(x, zIndices, xTable, derivOrder, termOrder, reservedIndices) {
  7. var result = 0;
  8. var reserved;
  9. var i;
  10. var j;
  11. if (derivOrder > 0) {
  12. for (i = 0; i < termOrder; i++) {
  13. reserved = false;
  14. for (j = 0; j < reservedIndices.length && !reserved; j++) {
  15. if (i === reservedIndices[j]) {
  16. reserved = true;
  17. }
  18. }
  19. if (!reserved) {
  20. reservedIndices.push(i);
  21. result += calculateCoefficientTerm(x, zIndices, xTable, derivOrder - 1, termOrder, reservedIndices);
  22. reservedIndices.splice(reservedIndices.length - 1, 1);
  23. }
  24. }
  25. return result;
  26. }
  27. result = 1;
  28. for (i = 0; i < termOrder; i++) {
  29. reserved = false;
  30. for (j = 0; j < reservedIndices.length && !reserved; j++) {
  31. if (i === reservedIndices[j]) {
  32. reserved = true;
  33. }
  34. }
  35. if (!reserved) {
  36. result *= x - xTable[zIndices[i]];
  37. }
  38. }
  39. return result;
  40. }
  41. /**
  42. * An {@link InterpolationAlgorithm} for performing Hermite interpolation.
  43. *
  44. * @exports HermitePolynomialApproximation
  45. */
  46. var HermitePolynomialApproximation = {
  47. type : 'Hermite'
  48. };
  49. /**
  50. * Given the desired degree, returns the number of data points required for interpolation.
  51. *
  52. * @param {Number} degree The desired degree of interpolation.
  53. * @param {Number} [inputOrder=0] The order of the inputs (0 means just the data, 1 means the data and its derivative, etc).
  54. * @returns {Number} The number of required data points needed for the desired degree of interpolation.
  55. * @exception {DeveloperError} degree must be 0 or greater.
  56. * @exception {DeveloperError} inputOrder must be 0 or greater.
  57. */
  58. HermitePolynomialApproximation.getRequiredDataPoints = function(degree, inputOrder) {
  59. inputOrder = defaultValue(inputOrder, 0);
  60. //>>includeStart('debug', pragmas.debug);
  61. if (!defined(degree)) {
  62. throw new DeveloperError('degree is required.');
  63. }
  64. if (degree < 0) {
  65. throw new DeveloperError('degree must be 0 or greater.');
  66. }
  67. if (inputOrder < 0) {
  68. throw new DeveloperError('inputOrder must be 0 or greater.');
  69. }
  70. //>>includeEnd('debug');
  71. return Math.max(Math.floor((degree + 1) / (inputOrder + 1)), 2);
  72. };
  73. /**
  74. * Interpolates values using Hermite Polynomial Approximation.
  75. *
  76. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  77. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  78. * in this array must be in increasing order and the same value must not occur twice in the array.
  79. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  80. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  81. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  82. * each independent variable value in xTable.
  83. * @param {Number[]} [result] An existing array into which to store the result.
  84. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  85. */
  86. HermitePolynomialApproximation.interpolateOrderZero = function(x, xTable, yTable, yStride, result) {
  87. if (!defined(result)) {
  88. result = new Array(yStride);
  89. }
  90. var i;
  91. var j;
  92. var d;
  93. var s;
  94. var len;
  95. var index;
  96. var length = xTable.length;
  97. var coefficients = new Array(yStride);
  98. for (i = 0; i < yStride; i++) {
  99. result[i] = 0;
  100. var l = new Array(length);
  101. coefficients[i] = l;
  102. for (j = 0; j < length; j++) {
  103. l[j] = [];
  104. }
  105. }
  106. var zIndicesLength = length, zIndices = new Array(zIndicesLength);
  107. for (i = 0; i < zIndicesLength; i++) {
  108. zIndices[i] = i;
  109. }
  110. var highestNonZeroCoef = length - 1;
  111. for (s = 0; s < yStride; s++) {
  112. for (j = 0; j < zIndicesLength; j++) {
  113. index = zIndices[j] * yStride + s;
  114. coefficients[s][0].push(yTable[index]);
  115. }
  116. for (i = 1; i < zIndicesLength; i++) {
  117. var nonZeroCoefficients = false;
  118. for (j = 0; j < zIndicesLength - i; j++) {
  119. var zj = xTable[zIndices[j]];
  120. var zn = xTable[zIndices[j + i]];
  121. var numerator;
  122. if (zn - zj <= 0) {
  123. index = zIndices[j] * yStride + yStride * i + s;
  124. numerator = yTable[index];
  125. coefficients[s][i].push(numerator / factorial(i));
  126. } else {
  127. numerator = (coefficients[s][i - 1][j + 1] - coefficients[s][i - 1][j]);
  128. coefficients[s][i].push(numerator / (zn - zj));
  129. }
  130. nonZeroCoefficients = nonZeroCoefficients || (numerator !== 0);
  131. }
  132. if (!nonZeroCoefficients) {
  133. highestNonZeroCoef = i - 1;
  134. }
  135. }
  136. }
  137. for (d = 0, len = 0; d <= len; d++) {
  138. for (i = d; i <= highestNonZeroCoef; i++) {
  139. var tempTerm = calculateCoefficientTerm(x, zIndices, xTable, d, i, []);
  140. for (s = 0; s < yStride; s++) {
  141. var coeff = coefficients[s][i][0];
  142. result[s + d * yStride] += coeff * tempTerm;
  143. }
  144. }
  145. }
  146. return result;
  147. };
  148. var arrayScratch = [];
  149. /**
  150. * Interpolates values using Hermite Polynomial Approximation.
  151. *
  152. * @param {Number} x The independent variable for which the dependent variables will be interpolated.
  153. * @param {Number[]} xTable The array of independent variables to use to interpolate. The values
  154. * in this array must be in increasing order and the same value must not occur twice in the array.
  155. * @param {Number[]} yTable The array of dependent variables to use to interpolate. For a set of three
  156. * dependent values (p,q,w) at time 1 and time 2 this should be as follows: {p1, q1, w1, p2, q2, w2}.
  157. * @param {Number} yStride The number of dependent variable values in yTable corresponding to
  158. * each independent variable value in xTable.
  159. * @param {Number} inputOrder The number of derivatives supplied for input.
  160. * @param {Number} outputOrder The number of derivatives desired for output.
  161. * @param {Number[]} [result] An existing array into which to store the result.
  162. *
  163. * @returns {Number[]} The array of interpolated values, or the result parameter if one was provided.
  164. */
  165. HermitePolynomialApproximation.interpolate = function(x, xTable, yTable, yStride, inputOrder, outputOrder, result) {
  166. var resultLength = yStride * (outputOrder + 1);
  167. if (!defined(result)) {
  168. result = new Array(resultLength);
  169. }
  170. for (var r = 0; r < resultLength; r++) {
  171. result[r] = 0;
  172. }
  173. var length = xTable.length;
  174. // The zIndices array holds copies of the addresses of the xTable values
  175. // in the range we're looking at. Even though this just holds information already
  176. // available in xTable this is a much more convenient format.
  177. var zIndices = new Array(length * (inputOrder + 1));
  178. var i;
  179. for (i = 0; i < length; i++) {
  180. for (var j = 0; j < (inputOrder + 1); j++) {
  181. zIndices[i * (inputOrder + 1) + j] = i;
  182. }
  183. }
  184. var zIndiceslength = zIndices.length;
  185. var coefficients = arrayScratch;
  186. var highestNonZeroCoef = fillCoefficientList(coefficients, zIndices, xTable, yTable, yStride, inputOrder);
  187. var reservedIndices = [];
  188. var tmp = zIndiceslength * (zIndiceslength + 1) / 2;
  189. var loopStop = Math.min(highestNonZeroCoef, outputOrder);
  190. for (var d = 0; d <= loopStop; d++) {
  191. for (i = d; i <= highestNonZeroCoef; i++) {
  192. reservedIndices.length = 0;
  193. var tempTerm = calculateCoefficientTerm(x, zIndices, xTable, d, i, reservedIndices);
  194. var dimTwo = Math.floor(i * (1 - i) / 2) + (zIndiceslength * i);
  195. for (var s = 0; s < yStride; s++) {
  196. var dimOne = Math.floor(s * tmp);
  197. var coef = coefficients[dimOne + dimTwo];
  198. result[s + d * yStride] += coef * tempTerm;
  199. }
  200. }
  201. }
  202. return result;
  203. };
  204. function fillCoefficientList(coefficients, zIndices, xTable, yTable, yStride, inputOrder) {
  205. var j;
  206. var index;
  207. var highestNonZero = -1;
  208. var zIndiceslength = zIndices.length;
  209. var tmp = zIndiceslength * (zIndiceslength + 1) / 2;
  210. for (var s = 0; s < yStride; s++) {
  211. var dimOne = Math.floor(s * tmp);
  212. for (j = 0; j < zIndiceslength; j++) {
  213. index = zIndices[j] * yStride * (inputOrder + 1) + s;
  214. coefficients[dimOne + j] = yTable[index];
  215. }
  216. for (var i = 1; i < zIndiceslength; i++) {
  217. var coefIndex = 0;
  218. var dimTwo = Math.floor(i * (1 - i) / 2) + (zIndiceslength * i);
  219. var nonZeroCoefficients = false;
  220. for (j = 0; j < zIndiceslength - i; j++) {
  221. var zj = xTable[zIndices[j]];
  222. var zn = xTable[zIndices[j + i]];
  223. var numerator;
  224. var coefficient;
  225. if (zn - zj <= 0) {
  226. index = zIndices[j] * yStride * (inputOrder + 1) + yStride * i + s;
  227. numerator = yTable[index];
  228. coefficient = (numerator / CesiumMath.factorial(i));
  229. coefficients[dimOne + dimTwo + coefIndex] = coefficient;
  230. coefIndex++;
  231. } else {
  232. var dimTwoMinusOne = Math.floor((i - 1) * (2 - i) / 2) + (zIndiceslength * (i - 1));
  233. numerator = coefficients[dimOne + dimTwoMinusOne + j + 1] - coefficients[dimOne + dimTwoMinusOne + j];
  234. coefficient = (numerator / (zn - zj));
  235. coefficients[dimOne + dimTwo + coefIndex] = coefficient;
  236. coefIndex++;
  237. }
  238. nonZeroCoefficients = nonZeroCoefficients || (numerator !== 0.0);
  239. }
  240. if (nonZeroCoefficients) {
  241. highestNonZero = Math.max(highestNonZero, i);
  242. }
  243. }
  244. }
  245. return highestNonZero;
  246. }
  247. export default HermitePolynomialApproximation;