function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

var Base = require('../../base');

var SimulateAnneal = /*#__PURE__*/function (_Base) {
  _inheritsLoose(SimulateAnneal, _Base);

  function SimulateAnneal() {
    return _Base.apply(this, arguments) || this;
  }

  var _proto = SimulateAnneal.prototype;

  _proto.getDefaultCfg = function getDefaultCfg() {
    return {
      // 最大移动距离
      maxMove: 5,
      // 线长的权重
      lineLength: 0.2,
      // 线碰撞权重
      intersect: 1,
      // 标签与标签碰撞权重
      labelToLabel: 30,
      // 标签与别的shape碰撞权重
      labelToShape: 30,
      // 标签偏移
      orient: 3,
      // 迭代次数
      iteration: 200,
      // 退火阈值
      threshold: 0.1
    };
  } // 简单的图形碰撞检测
  ;

  _proto._intersect = function _intersect(x1, x2, x3, x4, y1, y2, y3, y4) {
    var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
    var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
    var numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
    var mua = numera / denom;
    var mub = numerb / denom;

    if (!(mua < 0 || mua > 1 || mub < 0 || mub > 1)) {
      return true;
    }

    return false;
  } // 计算重排一个label后的能量值
  ;

  _proto.energy = function energy(index) {
    var self = this;
    var labels = self.get('labels');
    var shapes = self.get('shapes');
    var labelLen = labels.length;
    var label = labels[index];
    var shape = shapes[index];
    var bbox = label.getBBox();
    var energy = 0;
    var dx = labels[index].attr('x') - shapes[index].attr('x');
    var dy = labels[index].attr('y') - shapes[index].attr('y');
    var dist = Math.sqrt(dx * dx + dy * dy);

    if (dist > 0) {
      energy += dist * self.get('lineLength');
    }

    dx /= dist;
    dy /= dist;

    if (dx > 0 && dy > 0) {
      energy += 0;
    } else if (dx < 0 && dy > 0) {
      energy += self.get('orient');
    } else if (dx < 0 && dy < 0) {
      energy += self.get('orient') * 2;
    } else {
      energy += self.get('orient') * 3;
    }

    var overlap, overlapX, overlapY, temp, tempBBox, tempShape, tempShapeBBox;

    for (var i = 0; i < labelLen; i++) {
      temp = labels[i];
      tempBBox = temp.getBBox();
      tempShape = shapes[i];
      tempShapeBBox = tempShape.getBBox(); // 标签与标签碰撞增加能量

      if (i !== index) {
        overlap = self._intersect(shape.attr('x'), label.attr('x'), tempShape.attr('x'), temp.attr('x'), shape.attr('y'), label.attr('y'), tempShape.attr('y'), temp.attr('y'));

        if (overlap) {
          energy += self.get('intersect');
        }

        overlapX = Math.max(0, Math.min(tempBBox.maxX, bbox.maxX) - Math.max(tempBBox.minX, bbox.minX));
        overlapY = Math.max(0, Math.min(tempBBox.maxY, bbox.maxY) - Math.max(tempBBox.minY, bbox.minY));
        energy += overlapX * overlapY * self.get('labelToLabel');
      } // 标签与shape碰撞能量


      overlapX = Math.max(0, Math.min(tempShapeBBox.maxX, bbox.maxX) - Math.max(tempShapeBBox.minX, bbox.minX));
      overlapY = Math.max(0, Math.min(tempShapeBBox.maxY, bbox.maxY) - Math.max(tempShapeBBox.minY, bbox.minY));
      energy += overlapX * overlapY * self.get('labelToShape');
    }

    return energy;
  } // 蒙特卡罗模拟位移
  ;

  _proto.move = function move(current) {
    var self = this;
    var labels = this.get('labels');
    var random = Math.floor(Math.random() * labels.length);
    var label = labels[random];
    var origin = {
      x: labels[random].attr('x'),
      y: labels[random].attr('y')
    };
    var originEnergy = self.energy(random);
    var moveX = label.attr('x') + (Math.random() - 0.5) * self.get('maxMove');

    if (moveX < 0) {
      moveX = origin.x;
    }

    var moveY = label.attr('y') + (Math.random() - 0.5) * self.get('maxMove');

    if (moveY < 0) {
      moveY = origin.y;
    }

    label.attr({
      x: moveX,
      y: moveY
    });
    var newEnergy = self.energy(random);
    var d = newEnergy - originEnergy;

    if (Math.random() > Math.exp(-d / current)) {
      label.attr({
        x: origin.x,
        y: origin.y
      });
    }
  };

  _proto.cooling = function cooling(current, init, iterate) {
    return current - init / iterate;
  };

  _proto.adjust = function adjust(labels, shapes) {
    var self = this;
    var iteration = self.get('iteration');
    self.set('labels', labels);
    self.set('shapes', shapes);
    var initTime = 1;
    var currentTime = 1;

    for (var i = 0; i < iteration; i++) {
      for (var j = 0; j < labels.length; j++) {
        self.move(currentTime);
      }

      currentTime = self.cooling(currentTime, initTime, iteration);

      if (currentTime < self.get('threshold')) {
        break;
      }
    }
  };

  return SimulateAnneal;
}(Base);

module.exports = SimulateAnneal;