SampledProperty.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. import binarySearch from '../Core/binarySearch.js';
  2. import Check from '../Core/Check.js';
  3. import defaultValue from '../Core/defaultValue.js';
  4. import defined from '../Core/defined.js';
  5. import defineProperties from '../Core/defineProperties.js';
  6. import DeveloperError from '../Core/DeveloperError.js';
  7. import Event from '../Core/Event.js';
  8. import ExtrapolationType from '../Core/ExtrapolationType.js';
  9. import JulianDate from '../Core/JulianDate.js';
  10. import LinearApproximation from '../Core/LinearApproximation.js';
  11. var PackableNumber = {
  12. packedLength : 1,
  13. pack : function(value, array, startingIndex) {
  14. startingIndex = defaultValue(startingIndex, 0);
  15. array[startingIndex] = value;
  16. },
  17. unpack : function(array, startingIndex, result) {
  18. startingIndex = defaultValue(startingIndex, 0);
  19. return array[startingIndex];
  20. }
  21. };
  22. //We can't use splice for inserting new elements because function apply can't handle
  23. //a huge number of arguments. See https://code.google.com/p/chromium/issues/detail?id=56588
  24. function arrayInsert(array, startIndex, items) {
  25. var i;
  26. var arrayLength = array.length;
  27. var itemsLength = items.length;
  28. var newLength = arrayLength + itemsLength;
  29. array.length = newLength;
  30. if (arrayLength !== startIndex) {
  31. var q = arrayLength - 1;
  32. for (i = newLength - 1; i >= startIndex; i--) {
  33. array[i] = array[q--];
  34. }
  35. }
  36. for (i = 0; i < itemsLength; i++) {
  37. array[startIndex++] = items[i];
  38. }
  39. }
  40. function convertDate(date, epoch) {
  41. if (date instanceof JulianDate) {
  42. return date;
  43. }
  44. if (typeof date === 'string') {
  45. return JulianDate.fromIso8601(date);
  46. }
  47. return JulianDate.addSeconds(epoch, date, new JulianDate());
  48. }
  49. var timesSpliceArgs = [];
  50. var valuesSpliceArgs = [];
  51. function mergeNewSamples(epoch, times, values, newData, packedLength) {
  52. var newDataIndex = 0;
  53. var i;
  54. var prevItem;
  55. var timesInsertionPoint;
  56. var valuesInsertionPoint;
  57. var currentTime;
  58. var nextTime;
  59. while (newDataIndex < newData.length) {
  60. currentTime = convertDate(newData[newDataIndex], epoch);
  61. timesInsertionPoint = binarySearch(times, currentTime, JulianDate.compare);
  62. var timesSpliceArgsCount = 0;
  63. var valuesSpliceArgsCount = 0;
  64. if (timesInsertionPoint < 0) {
  65. //Doesn't exist, insert as many additional values as we can.
  66. timesInsertionPoint = ~timesInsertionPoint;
  67. valuesInsertionPoint = timesInsertionPoint * packedLength;
  68. prevItem = undefined;
  69. nextTime = times[timesInsertionPoint];
  70. while (newDataIndex < newData.length) {
  71. currentTime = convertDate(newData[newDataIndex], epoch);
  72. if ((defined(prevItem) && JulianDate.compare(prevItem, currentTime) >= 0) || (defined(nextTime) && JulianDate.compare(currentTime, nextTime) >= 0)) {
  73. break;
  74. }
  75. timesSpliceArgs[timesSpliceArgsCount++] = currentTime;
  76. newDataIndex = newDataIndex + 1;
  77. for (i = 0; i < packedLength; i++) {
  78. valuesSpliceArgs[valuesSpliceArgsCount++] = newData[newDataIndex];
  79. newDataIndex = newDataIndex + 1;
  80. }
  81. prevItem = currentTime;
  82. }
  83. if (timesSpliceArgsCount > 0) {
  84. valuesSpliceArgs.length = valuesSpliceArgsCount;
  85. arrayInsert(values, valuesInsertionPoint, valuesSpliceArgs);
  86. timesSpliceArgs.length = timesSpliceArgsCount;
  87. arrayInsert(times, timesInsertionPoint, timesSpliceArgs);
  88. }
  89. } else {
  90. //Found an exact match
  91. for (i = 0; i < packedLength; i++) {
  92. newDataIndex++;
  93. values[(timesInsertionPoint * packedLength) + i] = newData[newDataIndex];
  94. }
  95. newDataIndex++;
  96. }
  97. }
  98. }
  99. /**
  100. * A {@link Property} whose value is interpolated for a given time from the
  101. * provided set of samples and specified interpolation algorithm and degree.
  102. * @alias SampledProperty
  103. * @constructor
  104. *
  105. * @param {Number|Packable} type The type of property.
  106. * @param {Packable[]} [derivativeTypes] When supplied, indicates that samples will contain derivative information of the specified types.
  107. *
  108. *
  109. * @example
  110. * //Create a linearly interpolated Cartesian2
  111. * var property = new Cesium.SampledProperty(Cesium.Cartesian2);
  112. *
  113. * //Populate it with data
  114. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:00:00.00Z'), new Cesium.Cartesian2(0, 0));
  115. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-02T00:00:00.00Z'), new Cesium.Cartesian2(4, 7));
  116. *
  117. * //Retrieve an interpolated value
  118. * var result = property.getValue(Cesium.JulianDate.fromIso8601('2012-08-01T12:00:00.00Z'));
  119. *
  120. * @example
  121. * //Create a simple numeric SampledProperty that uses third degree Hermite Polynomial Approximation
  122. * var property = new Cesium.SampledProperty(Number);
  123. * property.setInterpolationOptions({
  124. * interpolationDegree : 3,
  125. * interpolationAlgorithm : Cesium.HermitePolynomialApproximation
  126. * });
  127. *
  128. * //Populate it with data
  129. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:00:00.00Z'), 1.0);
  130. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:01:00.00Z'), 6.0);
  131. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:02:00.00Z'), 12.0);
  132. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:03:30.00Z'), 5.0);
  133. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:06:30.00Z'), 2.0);
  134. *
  135. * //Samples can be added in any order.
  136. * property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:00:30.00Z'), 6.2);
  137. *
  138. * //Retrieve an interpolated value
  139. * var result = property.getValue(Cesium.JulianDate.fromIso8601('2012-08-01T00:02:34.00Z'));
  140. *
  141. * @see SampledPositionProperty
  142. */
  143. function SampledProperty(type, derivativeTypes) {
  144. //>>includeStart('debug', pragmas.debug);
  145. Check.defined('type', type);
  146. //>>includeEnd('debug');
  147. var innerType = type;
  148. if (innerType === Number) {
  149. innerType = PackableNumber;
  150. }
  151. var packedLength = innerType.packedLength;
  152. var packedInterpolationLength = defaultValue(innerType.packedInterpolationLength, packedLength);
  153. var inputOrder = 0;
  154. var innerDerivativeTypes;
  155. if (defined(derivativeTypes)) {
  156. var length = derivativeTypes.length;
  157. innerDerivativeTypes = new Array(length);
  158. for (var i = 0; i < length; i++) {
  159. var derivativeType = derivativeTypes[i];
  160. if (derivativeType === Number) {
  161. derivativeType = PackableNumber;
  162. }
  163. var derivativePackedLength = derivativeType.packedLength;
  164. packedLength += derivativePackedLength;
  165. packedInterpolationLength += defaultValue(derivativeType.packedInterpolationLength, derivativePackedLength);
  166. innerDerivativeTypes[i] = derivativeType;
  167. }
  168. inputOrder = length;
  169. }
  170. this._type = type;
  171. this._innerType = innerType;
  172. this._interpolationDegree = 1;
  173. this._interpolationAlgorithm = LinearApproximation;
  174. this._numberOfPoints = 0;
  175. this._times = [];
  176. this._values = [];
  177. this._xTable = [];
  178. this._yTable = [];
  179. this._packedLength = packedLength;
  180. this._packedInterpolationLength = packedInterpolationLength;
  181. this._updateTableLength = true;
  182. this._interpolationResult = new Array(packedInterpolationLength);
  183. this._definitionChanged = new Event();
  184. this._derivativeTypes = derivativeTypes;
  185. this._innerDerivativeTypes = innerDerivativeTypes;
  186. this._inputOrder = inputOrder;
  187. this._forwardExtrapolationType = ExtrapolationType.NONE;
  188. this._forwardExtrapolationDuration = 0;
  189. this._backwardExtrapolationType = ExtrapolationType.NONE;
  190. this._backwardExtrapolationDuration = 0;
  191. }
  192. defineProperties(SampledProperty.prototype, {
  193. /**
  194. * Gets a value indicating if this property is constant. A property is considered
  195. * constant if getValue always returns the same result for the current definition.
  196. * @memberof SampledProperty.prototype
  197. *
  198. * @type {Boolean}
  199. * @readonly
  200. */
  201. isConstant : {
  202. get : function() {
  203. return this._values.length === 0;
  204. }
  205. },
  206. /**
  207. * Gets the event that is raised whenever the definition of this property changes.
  208. * The definition is considered to have changed if a call to getValue would return
  209. * a different result for the same time.
  210. * @memberof SampledProperty.prototype
  211. *
  212. * @type {Event}
  213. * @readonly
  214. */
  215. definitionChanged : {
  216. get : function() {
  217. return this._definitionChanged;
  218. }
  219. },
  220. /**
  221. * Gets the type of property.
  222. * @memberof SampledProperty.prototype
  223. * @type {*}
  224. */
  225. type : {
  226. get : function() {
  227. return this._type;
  228. }
  229. },
  230. /**
  231. * Gets the derivative types used by this property.
  232. * @memberof SampledProperty.prototype
  233. * @type {Packable[]}
  234. */
  235. derivativeTypes : {
  236. get : function() {
  237. return this._derivativeTypes;
  238. }
  239. },
  240. /**
  241. * Gets the degree of interpolation to perform when retrieving a value.
  242. * @memberof SampledProperty.prototype
  243. * @type {Number}
  244. * @default 1
  245. */
  246. interpolationDegree : {
  247. get : function() {
  248. return this._interpolationDegree;
  249. }
  250. },
  251. /**
  252. * Gets the interpolation algorithm to use when retrieving a value.
  253. * @memberof SampledProperty.prototype
  254. * @type {InterpolationAlgorithm}
  255. * @default LinearApproximation
  256. */
  257. interpolationAlgorithm : {
  258. get : function() {
  259. return this._interpolationAlgorithm;
  260. }
  261. },
  262. /**
  263. * Gets or sets the type of extrapolation to perform when a value
  264. * is requested at a time after any available samples.
  265. * @memberof SampledProperty.prototype
  266. * @type {ExtrapolationType}
  267. * @default ExtrapolationType.NONE
  268. */
  269. forwardExtrapolationType : {
  270. get : function() {
  271. return this._forwardExtrapolationType;
  272. },
  273. set : function(value) {
  274. if (this._forwardExtrapolationType !== value) {
  275. this._forwardExtrapolationType = value;
  276. this._definitionChanged.raiseEvent(this);
  277. }
  278. }
  279. },
  280. /**
  281. * Gets or sets the amount of time to extrapolate forward before
  282. * the property becomes undefined. A value of 0 will extrapolate forever.
  283. * @memberof SampledProperty.prototype
  284. * @type {Number}
  285. * @default 0
  286. */
  287. forwardExtrapolationDuration : {
  288. get : function() {
  289. return this._forwardExtrapolationDuration;
  290. },
  291. set : function(value) {
  292. if (this._forwardExtrapolationDuration !== value) {
  293. this._forwardExtrapolationDuration = value;
  294. this._definitionChanged.raiseEvent(this);
  295. }
  296. }
  297. },
  298. /**
  299. * Gets or sets the type of extrapolation to perform when a value
  300. * is requested at a time before any available samples.
  301. * @memberof SampledProperty.prototype
  302. * @type {ExtrapolationType}
  303. * @default ExtrapolationType.NONE
  304. */
  305. backwardExtrapolationType : {
  306. get : function() {
  307. return this._backwardExtrapolationType;
  308. },
  309. set : function(value) {
  310. if (this._backwardExtrapolationType !== value) {
  311. this._backwardExtrapolationType = value;
  312. this._definitionChanged.raiseEvent(this);
  313. }
  314. }
  315. },
  316. /**
  317. * Gets or sets the amount of time to extrapolate backward
  318. * before the property becomes undefined. A value of 0 will extrapolate forever.
  319. * @memberof SampledProperty.prototype
  320. * @type {Number}
  321. * @default 0
  322. */
  323. backwardExtrapolationDuration : {
  324. get : function() {
  325. return this._backwardExtrapolationDuration;
  326. },
  327. set : function(value) {
  328. if (this._backwardExtrapolationDuration !== value) {
  329. this._backwardExtrapolationDuration = value;
  330. this._definitionChanged.raiseEvent(this);
  331. }
  332. }
  333. }
  334. });
  335. /**
  336. * Gets the value of the property at the provided time.
  337. *
  338. * @param {JulianDate} time The time for which to retrieve the value.
  339. * @param {Object} [result] The object to store the value into, if omitted, a new instance is created and returned.
  340. * @returns {Object} The modified result parameter or a new instance if the result parameter was not supplied.
  341. */
  342. SampledProperty.prototype.getValue = function(time, result) {
  343. //>>includeStart('debug', pragmas.debug);
  344. Check.defined('time', time);
  345. //>>includeEnd('debug');
  346. var times = this._times;
  347. var timesLength = times.length;
  348. if (timesLength === 0) {
  349. return undefined;
  350. }
  351. var timeout;
  352. var innerType = this._innerType;
  353. var values = this._values;
  354. var index = binarySearch(times, time, JulianDate.compare);
  355. if (index < 0) {
  356. index = ~index;
  357. if (index === 0) {
  358. var startTime = times[index];
  359. timeout = this._backwardExtrapolationDuration;
  360. if (this._backwardExtrapolationType === ExtrapolationType.NONE || (timeout !== 0 && JulianDate.secondsDifference(startTime, time) > timeout)) {
  361. return undefined;
  362. }
  363. if (this._backwardExtrapolationType === ExtrapolationType.HOLD) {
  364. return innerType.unpack(values, 0, result);
  365. }
  366. }
  367. if (index >= timesLength) {
  368. index = timesLength - 1;
  369. var endTime = times[index];
  370. timeout = this._forwardExtrapolationDuration;
  371. if (this._forwardExtrapolationType === ExtrapolationType.NONE || (timeout !== 0 && JulianDate.secondsDifference(time, endTime) > timeout)) {
  372. return undefined;
  373. }
  374. if (this._forwardExtrapolationType === ExtrapolationType.HOLD) {
  375. index = timesLength - 1;
  376. return innerType.unpack(values, index * innerType.packedLength, result);
  377. }
  378. }
  379. var xTable = this._xTable;
  380. var yTable = this._yTable;
  381. var interpolationAlgorithm = this._interpolationAlgorithm;
  382. var packedInterpolationLength = this._packedInterpolationLength;
  383. var inputOrder = this._inputOrder;
  384. if (this._updateTableLength) {
  385. this._updateTableLength = false;
  386. var numberOfPoints = Math.min(interpolationAlgorithm.getRequiredDataPoints(this._interpolationDegree, inputOrder), timesLength);
  387. if (numberOfPoints !== this._numberOfPoints) {
  388. this._numberOfPoints = numberOfPoints;
  389. xTable.length = numberOfPoints;
  390. yTable.length = numberOfPoints * packedInterpolationLength;
  391. }
  392. }
  393. var degree = this._numberOfPoints - 1;
  394. if (degree < 1) {
  395. return undefined;
  396. }
  397. var firstIndex = 0;
  398. var lastIndex = timesLength - 1;
  399. var pointsInCollection = lastIndex - firstIndex + 1;
  400. if (pointsInCollection >= degree + 1) {
  401. var computedFirstIndex = index - ((degree / 2) | 0) - 1;
  402. if (computedFirstIndex < firstIndex) {
  403. computedFirstIndex = firstIndex;
  404. }
  405. var computedLastIndex = computedFirstIndex + degree;
  406. if (computedLastIndex > lastIndex) {
  407. computedLastIndex = lastIndex;
  408. computedFirstIndex = computedLastIndex - degree;
  409. if (computedFirstIndex < firstIndex) {
  410. computedFirstIndex = firstIndex;
  411. }
  412. }
  413. firstIndex = computedFirstIndex;
  414. lastIndex = computedLastIndex;
  415. }
  416. var length = lastIndex - firstIndex + 1;
  417. // Build the tables
  418. for (var i = 0; i < length; ++i) {
  419. xTable[i] = JulianDate.secondsDifference(times[firstIndex + i], times[lastIndex]);
  420. }
  421. if (!defined(innerType.convertPackedArrayForInterpolation)) {
  422. var destinationIndex = 0;
  423. var packedLength = this._packedLength;
  424. var sourceIndex = firstIndex * packedLength;
  425. var stop = (lastIndex + 1) * packedLength;
  426. while (sourceIndex < stop) {
  427. yTable[destinationIndex] = values[sourceIndex];
  428. sourceIndex++;
  429. destinationIndex++;
  430. }
  431. } else {
  432. innerType.convertPackedArrayForInterpolation(values, firstIndex, lastIndex, yTable);
  433. }
  434. // Interpolate!
  435. var x = JulianDate.secondsDifference(time, times[lastIndex]);
  436. var interpolationResult;
  437. if (inputOrder === 0 || !defined(interpolationAlgorithm.interpolate)) {
  438. interpolationResult = interpolationAlgorithm.interpolateOrderZero(x, xTable, yTable, packedInterpolationLength, this._interpolationResult);
  439. } else {
  440. var yStride = Math.floor(packedInterpolationLength / (inputOrder + 1));
  441. interpolationResult = interpolationAlgorithm.interpolate(x, xTable, yTable, yStride, inputOrder, inputOrder, this._interpolationResult);
  442. }
  443. if (!defined(innerType.unpackInterpolationResult)) {
  444. return innerType.unpack(interpolationResult, 0, result);
  445. }
  446. return innerType.unpackInterpolationResult(interpolationResult, values, firstIndex, lastIndex, result);
  447. }
  448. return innerType.unpack(values, index * this._packedLength, result);
  449. };
  450. /**
  451. * Sets the algorithm and degree to use when interpolating a value.
  452. *
  453. * @param {Object} [options] Object with the following properties:
  454. * @param {InterpolationAlgorithm} [options.interpolationAlgorithm] The new interpolation algorithm. If undefined, the existing property will be unchanged.
  455. * @param {Number} [options.interpolationDegree] The new interpolation degree. If undefined, the existing property will be unchanged.
  456. */
  457. SampledProperty.prototype.setInterpolationOptions = function(options) {
  458. if (!defined(options)) {
  459. return;
  460. }
  461. var valuesChanged = false;
  462. var interpolationAlgorithm = options.interpolationAlgorithm;
  463. var interpolationDegree = options.interpolationDegree;
  464. if (defined(interpolationAlgorithm) && this._interpolationAlgorithm !== interpolationAlgorithm) {
  465. this._interpolationAlgorithm = interpolationAlgorithm;
  466. valuesChanged = true;
  467. }
  468. if (defined(interpolationDegree) && this._interpolationDegree !== interpolationDegree) {
  469. this._interpolationDegree = interpolationDegree;
  470. valuesChanged = true;
  471. }
  472. if (valuesChanged) {
  473. this._updateTableLength = true;
  474. this._definitionChanged.raiseEvent(this);
  475. }
  476. };
  477. /**
  478. * Adds a new sample.
  479. *
  480. * @param {JulianDate} time The sample time.
  481. * @param {Packable} value The value at the provided time.
  482. * @param {Packable[]} [derivatives] The array of derivatives at the provided time.
  483. */
  484. SampledProperty.prototype.addSample = function(time, value, derivatives) {
  485. var innerDerivativeTypes = this._innerDerivativeTypes;
  486. var hasDerivatives = defined(innerDerivativeTypes);
  487. //>>includeStart('debug', pragmas.debug);
  488. Check.defined('time', time);
  489. Check.defined('value', value);
  490. if (hasDerivatives) {
  491. Check.defined('derivatives', derivatives);
  492. }
  493. //>>includeEnd('debug');
  494. var innerType = this._innerType;
  495. var data = [];
  496. data.push(time);
  497. innerType.pack(value, data, data.length);
  498. if (hasDerivatives) {
  499. var derivativesLength = innerDerivativeTypes.length;
  500. for (var x = 0; x < derivativesLength; x++) {
  501. innerDerivativeTypes[x].pack(derivatives[x], data, data.length);
  502. }
  503. }
  504. mergeNewSamples(undefined, this._times, this._values, data, this._packedLength);
  505. this._updateTableLength = true;
  506. this._definitionChanged.raiseEvent(this);
  507. };
  508. /**
  509. * Adds an array of samples.
  510. *
  511. * @param {JulianDate[]} times An array of JulianDate instances where each index is a sample time.
  512. * @param {Packable[]} values The array of values, where each value corresponds to the provided times index.
  513. * @param {Array[]} [derivativeValues] An array where each item is the array of derivatives at the equivalent time index.
  514. *
  515. * @exception {DeveloperError} times and values must be the same length.
  516. * @exception {DeveloperError} times and derivativeValues must be the same length.
  517. */
  518. SampledProperty.prototype.addSamples = function(times, values, derivativeValues) {
  519. var innerDerivativeTypes = this._innerDerivativeTypes;
  520. var hasDerivatives = defined(innerDerivativeTypes);
  521. //>>includeStart('debug', pragmas.debug);
  522. Check.defined('times', times);
  523. Check.defined('values', values);
  524. if (times.length !== values.length) {
  525. throw new DeveloperError('times and values must be the same length.');
  526. }
  527. if (hasDerivatives && (!defined(derivativeValues) || derivativeValues.length !== times.length)) {
  528. throw new DeveloperError('times and derivativeValues must be the same length.');
  529. }
  530. //>>includeEnd('debug');
  531. var innerType = this._innerType;
  532. var length = times.length;
  533. var data = [];
  534. for (var i = 0; i < length; i++) {
  535. data.push(times[i]);
  536. innerType.pack(values[i], data, data.length);
  537. if (hasDerivatives) {
  538. var derivatives = derivativeValues[i];
  539. var derivativesLength = innerDerivativeTypes.length;
  540. for (var x = 0; x < derivativesLength; x++) {
  541. innerDerivativeTypes[x].pack(derivatives[x], data, data.length);
  542. }
  543. }
  544. }
  545. mergeNewSamples(undefined, this._times, this._values, data, this._packedLength);
  546. this._updateTableLength = true;
  547. this._definitionChanged.raiseEvent(this);
  548. };
  549. /**
  550. * Adds samples as a single packed array where each new sample is represented as a date,
  551. * followed by the packed representation of the corresponding value and derivatives.
  552. *
  553. * @param {Number[]} packedSamples The array of packed samples.
  554. * @param {JulianDate} [epoch] If any of the dates in packedSamples are numbers, they are considered an offset from this epoch, in seconds.
  555. */
  556. SampledProperty.prototype.addSamplesPackedArray = function(packedSamples, epoch) {
  557. //>>includeStart('debug', pragmas.debug);
  558. Check.defined('packedSamples', packedSamples);
  559. //>>includeEnd('debug');
  560. mergeNewSamples(epoch, this._times, this._values, packedSamples, this._packedLength);
  561. this._updateTableLength = true;
  562. this._definitionChanged.raiseEvent(this);
  563. };
  564. /**
  565. * Removes a sample at the given time, if present.
  566. *
  567. * @param {JulianDate} time The sample time.
  568. * @returns {Boolean} <code>true</code> if a sample at time was removed, <code>false</code> otherwise.
  569. */
  570. SampledProperty.prototype.removeSample = function(time) {
  571. //>>includeStart('debug', pragmas.debug);
  572. Check.defined('time', time);
  573. //>>includeEnd('debug');
  574. var index = binarySearch(this._times, time, JulianDate.compare);
  575. if (index < 0) {
  576. return false;
  577. }
  578. removeSamples(this, index, 1);
  579. return true;
  580. };
  581. function removeSamples(property, startIndex, numberToRemove) {
  582. var packedLength = property._packedLength;
  583. property._times.splice(startIndex, numberToRemove);
  584. property._values.splice(startIndex * packedLength, numberToRemove * packedLength);
  585. property._updateTableLength = true;
  586. property._definitionChanged.raiseEvent(property);
  587. }
  588. /**
  589. * Removes all samples for the given time interval.
  590. *
  591. * @param {TimeInterval} time The time interval for which to remove all samples.
  592. */
  593. SampledProperty.prototype.removeSamples = function(timeInterval) {
  594. //>>includeStart('debug', pragmas.debug);
  595. Check.defined('timeInterval', timeInterval);
  596. //>>includeEnd('debug');
  597. var times = this._times;
  598. var startIndex = binarySearch(times, timeInterval.start, JulianDate.compare);
  599. if (startIndex < 0) {
  600. startIndex = ~startIndex;
  601. } else if (!timeInterval.isStartIncluded) {
  602. ++startIndex;
  603. }
  604. var stopIndex = binarySearch(times, timeInterval.stop, JulianDate.compare);
  605. if (stopIndex < 0) {
  606. stopIndex = ~stopIndex;
  607. } else if (timeInterval.isStopIncluded) {
  608. ++stopIndex;
  609. }
  610. removeSamples(this, startIndex, stopIndex - startIndex);
  611. };
  612. /**
  613. * Compares this property to the provided property and returns
  614. * <code>true</code> if they are equal, <code>false</code> otherwise.
  615. *
  616. * @param {Property} [other] The other property.
  617. * @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
  618. */
  619. SampledProperty.prototype.equals = function(other) {
  620. if (this === other) {
  621. return true;
  622. }
  623. if (!defined(other)) {
  624. return false;
  625. }
  626. if (this._type !== other._type || //
  627. this._interpolationDegree !== other._interpolationDegree || //
  628. this._interpolationAlgorithm !== other._interpolationAlgorithm) {
  629. return false;
  630. }
  631. var derivativeTypes = this._derivativeTypes;
  632. var hasDerivatives = defined(derivativeTypes);
  633. var otherDerivativeTypes = other._derivativeTypes;
  634. var otherHasDerivatives = defined(otherDerivativeTypes);
  635. if (hasDerivatives !== otherHasDerivatives) {
  636. return false;
  637. }
  638. var i;
  639. var length;
  640. if (hasDerivatives) {
  641. length = derivativeTypes.length;
  642. if (length !== otherDerivativeTypes.length) {
  643. return false;
  644. }
  645. for (i = 0; i < length; i++) {
  646. if (derivativeTypes[i] !== otherDerivativeTypes[i]) {
  647. return false;
  648. }
  649. }
  650. }
  651. var times = this._times;
  652. var otherTimes = other._times;
  653. length = times.length;
  654. if (length !== otherTimes.length) {
  655. return false;
  656. }
  657. for (i = 0; i < length; i++) {
  658. if (!JulianDate.equals(times[i], otherTimes[i])) {
  659. return false;
  660. }
  661. }
  662. var values = this._values;
  663. var otherValues = other._values;
  664. for (i = 0; i < length; i++) {
  665. if (values[i] !== otherValues[i]) {
  666. return false;
  667. }
  668. }
  669. return true;
  670. };
  671. //Exposed for testing.
  672. SampledProperty._mergeNewSamples = mergeNewSamples;
  673. export default SampledProperty;