All files / engine/Source/Core arrayRemoveDuplicates.js

100% Statements 36/36
100% Branches 28/28
100% Functions 1/1
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130        1x                                                                                                     770x     770x 1x     769x 769x   769x 769x 127x       642x           642x       642x   642x 463957x 463957x 201x 146x 146x 146x   201x 27x     463756x 57x 57x 57x 26x     463756x       642x       21x 4x 3x   1x       21x 17x   4x       642x        
import Check from "./Check.js";
import defined from "./defined.js";
import CesiumMath from "./Math.js";
 
const removeDuplicatesEpsilon = CesiumMath.EPSILON10;
 
/**
 * Removes adjacent duplicate values in an array of values.
 *
 * @param {any[]} [values] The array of values.
 * @param {Function} equalsEpsilon Function to compare values with an epsilon. Boolean equalsEpsilon(left, right, epsilon).
 * @param {boolean} [wrapAround=false] Compare the last value in the array against the first value. If they are equal, the last value is removed.
 * @param {number[]} [removedIndices=undefined] Store the indices that correspond to the duplicate items removed from the array, if there were any.
 * @returns {any[]|undefined} A new array of values with no adjacent duplicate values or the input array if no duplicates were found.
 *
 * @example
 * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0), (1.0, 1.0, 1.0)]
 * const values = [
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0),
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0),
 *     new Cesium.Cartesian3(2.0, 2.0, 2.0),
 *     new Cesium.Cartesian3(3.0, 3.0, 3.0),
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0)];
 * const nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon);
 *
 * @example
 * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)]
 * const values = [
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0),
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0),
 *     new Cesium.Cartesian3(2.0, 2.0, 2.0),
 *     new Cesium.Cartesian3(3.0, 3.0, 3.0),
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0)];
 * const nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
 *
 * @example
 * // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)]
 * // removedIndices will be equal to [1, 3, 5]
 * const values = [
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0),
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0),
 *     new Cesium.Cartesian3(2.0, 2.0, 2.0),
 *     new Cesium.Cartesian3(2.0, 2.0, 2.0),
 *     new Cesium.Cartesian3(3.0, 3.0, 3.0),
 *     new Cesium.Cartesian3(1.0, 1.0, 1.0)];
 * const nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
 * @private
 */
function arrayRemoveDuplicates(
  values,
  equalsEpsilon,
  wrapAround,
  removedIndices,
) {
  //>>includeStart('debug', pragmas.debug);
  Check.defined("equalsEpsilon", equalsEpsilon);
  //>>includeEnd('debug');
 
  if (!defined(values)) {
    return undefined;
  }
 
  wrapAround = wrapAround ?? false;
  const storeRemovedIndices = defined(removedIndices);
 
  const length = values.length;
  if (length < 2) {
    return values;
  }
 
  let i;
  let v0 = values[0];
  let v1;
 
  // We only want to create a new array if there are duplicates in the array.
  // As such, cleanedValues is undefined until it encounters the first duplicate, if it exists.
  let cleanedValues;
  let lastCleanIndex = 0;
 
  // removedIndexLCI keeps track of where lastCleanIndex would be if it were sorted into the removedIndices array.
  // In case of arrays such as [A, B, C, ..., A, A, A], removedIndices will not be sorted properly without this.
  let removedIndexLCI = -1;
 
  for (i = 1; i < length; ++i) {
    v1 = values[i];
    if (equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
      if (!defined(cleanedValues)) {
        cleanedValues = values.slice(0, i);
        lastCleanIndex = i - 1;
        removedIndexLCI = 0;
      }
      if (storeRemovedIndices) {
        removedIndices.push(i);
      }
    } else {
      if (defined(cleanedValues)) {
        cleanedValues.push(v1);
        lastCleanIndex = i;
        if (storeRemovedIndices) {
          removedIndexLCI = removedIndices.length;
        }
      }
      v0 = v1;
    }
  }
 
  if (
    wrapAround &&
    equalsEpsilon(values[0], values[length - 1], removeDuplicatesEpsilon)
  ) {
    if (storeRemovedIndices) {
      if (defined(cleanedValues)) {
        removedIndices.splice(removedIndexLCI, 0, lastCleanIndex);
      } else {
        removedIndices.push(length - 1);
      }
    }
 
    if (defined(cleanedValues)) {
      cleanedValues.length -= 1;
    } else {
      cleanedValues = values.slice(0, -1);
    }
  }
 
  return defined(cleanedValues) ? cleanedValues : values;
}
 
export default arrayRemoveDuplicates;