"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.xPoints = exports.sinY = exports.pointsToAForAbsolute = exports.pointsToABForExponential = exports.pointsToABC = exports.parabolaFromTwoPoints = exports.parabolaFromThreePoints = exports.parabola = exports.getAmplitudeAndFreq = exports.exponentialFromTwoPoints = exports.exponential = exports["default"] = exports.buildDataPoints = exports.absoluteFromTwoPoints = exports.absolute = exports.FREQ_DIVIDER = void 0;

var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

var _debug = _interopRequireDefault(require("debug"));

var _pointGeometry = _interopRequireDefault(require("@mapbox/point-geometry"));

var _lodash = _interopRequireDefault(require("lodash"));

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

var log = (0, _debug["default"])('pie-lib:graphing:tools:utils');
var FREQ_DIVIDER = 16;
exports.FREQ_DIVIDER = FREQ_DIVIDER;

var getAmplitudeAndFreq = function getAmplitudeAndFreq(root, edge) {
  if (!edge) {
    return {
      freq: 0,
      amplitude: 0
    };
  }

  if (root.x == edge.x) {
    return {
      freq: 0,
      amplitude: 0
    };
  }

  var r = new _pointGeometry["default"](root.x, root.y);
  var e = new _pointGeometry["default"](edge.x, edge.y);
  var d = e.sub(r); // edge point describes 1/4 of the freq

  return {
    freq: d.x * 4,
    amplitude: d.y
  };
};
/**
 * build the x points with root as the anchor.
 */


exports.getAmplitudeAndFreq = getAmplitudeAndFreq;

var xPoints = function xPoints(root, freq, min, max) {
  freq = Math.abs(freq);
  log('[xPoints] root:', root, 'freq:', freq, ' min:', min, ' max:', max);

  var leftpoints = _lodash["default"].rangeRight(root, min - freq, freq * -1);

  var rightpoints = _lodash["default"].range(root + freq, max + freq, freq);

  return _lodash["default"].concat(leftpoints, rightpoints);
};
/**
 * Calculate y for x value using amp, freq and shift
 * https://www.desmos.com/calculator/f1psfoiiv6
 */


exports.xPoints = xPoints;

var sinY = function sinY(amplitude, freq, shift) {
  return function (x) {
    shift = _objectSpread({
      phase: 0,
      vertical: 0
    }, shift);
    var TWO_PI = Math.PI * 2;
    var num = TWO_PI * (x - shift.phase);
    var frac = num / freq;
    var sin = Math.sin(frac);
    var sinFloat = parseFloat(sin).toFixed(10);
    return amplitude * sinFloat + shift.vertical;
  };
};
/**
 * You need three points for the quadratic eq, so we mirror the edge point
 * https://www.desmos.com/calculator/xhz1xqgpca
 */


exports.sinY = sinY;

var parabolaFromTwoPoints = function parabolaFromTwoPoints(root, edge) {
  edge = edge || _objectSpread({}, root);
  var mirrorEdge = {
    x: root.x - (edge.x - root.x),
    y: edge.y
  };
  return parabolaFromThreePoints(root, edge, mirrorEdge);
};

exports.parabolaFromTwoPoints = parabolaFromTwoPoints;

var parabolaFromThreePoints = function parabolaFromThreePoints(one, two, three) {
  log(one, two, three);

  var _pointsToABC = pointsToABC(one, two, three),
      a = _pointsToABC.a,
      b = _pointsToABC.b,
      c = _pointsToABC.c;

  log(a, b, c);
  return parabola(a, b, c);
};
/** derive a,b,c from the 3 points */


exports.parabolaFromThreePoints = parabolaFromThreePoints;

var pointsToABC = function pointsToABC(one, two, three) {
  var a1 = Math.pow(one.x, 2) * -1 + Math.pow(two.x, 2);
  var b1 = one.x * -1 + two.x;
  var d1 = one.y * -1 + two.y;
  var a2 = Math.pow(two.x, 2) * -1 + Math.pow(three.x, 2);
  var b2 = two.x * -1 + three.x;
  var d2 = two.y * -1 + three.y;
  var bMult = b2 / b1 * -1;
  var a3 = bMult * a1 + a2;
  var d3 = bMult * d1 + d2;
  var a = d3 / a3;
  var b = (d1 - a1 * a) / b1;
  var c = one.y - a * Math.pow(one.x, 2) - b * one.x;
  return {
    a: a,
    b: b,
    c: c
  };
};
/**
 * y=ax^2+bx+c
 */


exports.pointsToABC = pointsToABC;

var parabola = function parabola(a, b, c) {
  return function (x) {
    return a * Math.pow(x, 2) + b * x + c;
  };
};
/**
 * Absolute value from two points Root (Vertex) the point where the two rays intersect and edge One point on a ray.
 * @param root 1st point selected on graph
 * @param edge 2nd point selected on graph
 * https://www.desmos.com/calculator/rarxiatpip
 */


exports.parabola = parabola;

var absoluteFromTwoPoints = function absoluteFromTwoPoints(root, edge) {
  edge = edge || _objectSpread({}, root);
  var a = pointsToAForAbsolute(root, edge);
  return absolute(a, root.x, root.y);
};
/*
 * Finds value of a in y=a*abs(x-h)+k function
 * @param one 1st point
 * @param two 2nd point
 * */


exports.absoluteFromTwoPoints = absoluteFromTwoPoints;

var pointsToAForAbsolute = function pointsToAForAbsolute(one, two) {
  var y1 = two.y - one.y;
  var x1 = two.x - one.x;
  var a = y1 / x1;

  if (two.x < one.x) {
    a = a * -1;
  }

  return a;
};
/**
 * y=a*abs(x-h)+k
 */


exports.pointsToAForAbsolute = pointsToAForAbsolute;

var absolute = function absolute(a, h, k) {
  return function (x) {
    return a * Math.abs(x - h) + k;
  };
};
/**
 * Exponential from two points on exponential graph.
 * @param root 1st point selected on graph
 * @param edge 2nd point selected on graph
 * https://www.desmos.com/calculator/3fisjexbvp
 */


exports.absolute = absolute;

var exponentialFromTwoPoints = function exponentialFromTwoPoints(root, edge) {
  edge = edge || _objectSpread({}, root);

  var _pointsToABForExponen = pointsToABForExponential(root, edge),
      a = _pointsToABForExponen.a,
      b = _pointsToABForExponen.b;

  return exponential(a, b);
};
/*
 * Finds value of a and b in y=a*(b)^x function
 * @param one 1st point
 * @param two 2nd point
 * */


exports.exponentialFromTwoPoints = exponentialFromTwoPoints;

var pointsToABForExponential = function pointsToABForExponential(one, two) {
  var p = one.y / two.y;
  var r = 1 / (one.x - two.x);
  var b = Math.pow(p, r);
  var a = one.y / Math.pow(b, one.x);
  return {
    a: a,
    b: b
  };
};
/**
 * y=a*(b)^x
 */


exports.pointsToABForExponential = pointsToABForExponential;

var exponential = function exponential(a, b) {
  return function (x) {
    return a * Math.pow(b, x);
  };
};
/**
 * Generate a set of data points, add spacing before min and after max if there is space between minx + min and maxX and max
 * @param {*} domain
 * @param {*} range
 * @param {*} root
 * @param {*} edge
 * @param {*} yFn
 * @param {*} excludeOutsidePoints
 */


exports.exponential = exponential;

var buildDataPoints = function buildDataPoints(domain, range, root, edge, yFn) {
  var excludeOutsidePoints = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
  log('[buildDataPoints] domain:', domain, 'range:', range, 'root:', root, 'edge:', edge);
  domain = _objectSpread({
    min: 0,
    max: 0,
    step: 1
  }, domain);
  range = _objectSpread({
    min: 0,
    max: 0,
    step: 1
  }, range);
  edge = edge ? edge : _objectSpread({}, root);
  var minX = Math.min(root.x, edge.x);
  var xPts = xPoints(minX, domain.step, domain.min - domain.step, domain.max + domain.step);
  log('[buildDataPoints]:xPts:', xPts);
  var startIndex = -1;
  var endIndex = -1; // generate points based on the yFn

  var points = xPts.map(function (v) {
    return new _pointGeometry["default"](v, yFn(v));
  });

  if (!excludeOutsidePoints) {
    return points;
  } // exclude the points with y outside range min and max


  var filteredPoints = points.reduce(function (acc, val, index) {
    if (val.y >= range.min - range.step && val.y <= range.max + range.step) {
      if (startIndex === -1) {
        startIndex = index;
      }

      if (endIndex < index) {
        endIndex = index;
      }

      return [].concat((0, _toConsumableArray2["default"])(acc), [val]);
    }

    return acc;
  }, []); // add the first value outside range min and max smaller than range.min if exists

  if (startIndex - 1 >= 0) {
    filteredPoints.unshift(points[startIndex - 1]);
  } // add the first value outside range min and max greater than range.min if exists


  if (endIndex + 1 <= points.length - 1) {
    filteredPoints.push(points[endIndex + 1]);
  }

  return points;
};

exports.buildDataPoints = buildDataPoints;
var _default = {
  FREQ_DIVIDER: FREQ_DIVIDER,
  getAmplitudeAndFreq: getAmplitudeAndFreq,
  xPoints: xPoints,
  sinY: sinY,
  parabolaFromTwoPoints: parabolaFromTwoPoints,
  parabolaFromThreePoints: parabolaFromThreePoints,
  pointsToABC: pointsToABC,
  parabola: parabola,
  absoluteFromTwoPoints: absoluteFromTwoPoints,
  pointsToAForAbsolute: pointsToAForAbsolute,
  absolute: absolute,
  exponentialFromTwoPoints: exponentialFromTwoPoints,
  pointsToABForExponential: pointsToABForExponential,
  exponential: exponential,
  buildDataPoints: buildDataPoints
};
exports["default"] = _default;
//# sourceMappingURL=index.js.map