src/math/index.js

// namespaces
var dwv = dwv || {};
dwv.math = dwv.math || {};

/**
 * Immutable index.
 * Warning: the input array is NOT cloned, modifying it will
 *  modify the index values.
 *
 * @class
 * @param {Array} values The index values.
 */
dwv.math.Index = function (values) {
  if (!values || typeof values === 'undefined') {
    throw new Error('Cannot create index with no values.');
  }
  if (values.length === 0) {
    throw new Error('Cannot create index with empty values.');
  }
  var valueCheck = function (val) {
    return !isNaN(val);
  };
  if (!values.every(valueCheck)) {
    throw new Error('Cannot create index with non number values.');
  }

  /**
   * Get the index value at the given array index.
   *
   * @param {number} i The index to get.
   * @returns {number} The value.
   */
  this.get = function (i) {
    return values[i];
  };

  /**
   * Get the length of the index.
   *
   * @returns {number} The length.
   */
  this.length = function () {
    return values.length;
  };

  /**
   * Get a string representation of the Index.
   *
   * @returns {string} The Index as a string.
   */
  this.toString = function () {
    return '(' + values.toString() + ')';
  };

  /**
   * Get the values of this index.
   *
   * @returns {Array} The array of values.
   */
  this.getValues = function () {
    return values.slice();
  };

}; // Index class

/**
 * Check if the input index can be compared to this one.
 *
 * @param {dwv.math.Index} rhs The index to compare to.
 * @returns {boolean} True if both indices are comparable.
 */
dwv.math.Index.prototype.canCompare = function (rhs) {
  // check input
  if (!rhs) {
    return false;
  }
  // check length
  if (this.length() !== rhs.length()) {
    return false;
  }
  // seems ok!
  return true;
};

/**
 * Check for Index equality.
 *
 * @param {dwv.math.Index} rhs The index to compare to.
 * @returns {boolean} True if both indices are equal.
 */
dwv.math.Index.prototype.equals = function (rhs) {
  // check if can compare
  if (!this.canCompare(rhs)) {
    return false;
  }
  // check values
  for (var i = 0, leni = this.length(); i < leni; ++i) {
    if (this.get(i) !== rhs.get(i)) {
      return false;
    }
  }
  // seems ok!
  return true;
};

/**
 * Add another index to this one.
 *
 * @param {dwv.math.Index} rhs The index to add.
 * @returns {dwv.math.Index} The index representing the sum of both indices.
 */
dwv.math.Index.prototype.add = function (rhs) {
  // check if can compare
  if (!this.canCompare(rhs)) {
    return null;
  }
  // add values
  var values = [];
  for (var i = 0, leni = this.length(); i < leni; ++i) {
    values.push(this.get(i) + rhs.get(i));
  }
  // seems ok!
  return new dwv.math.Index(values);
};

/**
 * Get the current index with a new 2D base.
 *
 * @param {number} i The new 0 index.
 * @param {number} j The new 1 index.
 * @returns {dwv.math.Index} The new index.
 */
dwv.math.Index.prototype.getWithNew2D = function (i, j) {
  var values = [i, j];
  for (var l = 2, lenl = this.length(); l < lenl; ++l) {
    values.push(this.get(l));
  }
  return new dwv.math.Index(values);
};

/**
 * Get an index with values set to 0 and the input size.
 *
 * @param {number} size The size of the index.
 * @returns {dwv.math.Index} The zero index.
 */
dwv.math.getZeroIndex = function (size) {
  var values = new Array(size);
  values.fill(0);
  return new dwv.math.Index(values);
};

/**
 * Get a string id from the index values in the form of: '#0-1_#1-2'.
 *
 * @param {Array} dims Optional list of dimensions to use.
 * @returns {string} The string id.
 */
dwv.math.Index.prototype.toStringId = function (dims) {
  if (typeof dims === 'undefined') {
    dims = [];
    for (var j = 0; j < this.length(); ++j) {
      dims.push(j);
    }
  }
  for (var ii = 0; ii < dims.length; ++ii) {
    if (dims[ii] >= this.length()) {
      throw new Error('Non valid dimension for toStringId.');
    }
  }
  var res = '';
  for (var i = 0; i < dims.length; ++i) {
    if (i !== 0) {
      res += '_';
    }
    res += '#' + dims[i] + '-' + this.get(dims[i]);
  }
  return res;
};

/**
 * Get an index from an id string in the form of: '#0-1_#1-2'
 * (result of index.toStringId).
 *
 * @param {string} inputStr The input string.
 * @returns {dwv.math.Index} The corresponding index.
 */
dwv.math.getIndexFromStringId = function (inputStr) {
  // split ids
  var strIds = inputStr.split('_');
  // get the size of the index
  var pointLength = 0;
  var dim;
  for (var i = 0; i < strIds.length; ++i) {
    dim = parseInt(strIds[i].substring(1, 2), 10);
    if (dim > pointLength) {
      pointLength = dim;
    }
  }
  if (pointLength === 0) {
    throw new Error('No dimension found in point stringId');
  }
  // default values
  var values = new Array(pointLength);
  values.fill(0);
  // get other values from the input string
  for (var j = 0; j < strIds.length; ++j) {
    dim = parseInt(strIds[j].substring(1, 3), 10);
    var value = parseInt(strIds[j].substring(3), 10);
    values[dim] = value;
  }
  return new dwv.math.Point(values);
};