text: "use strict";
  /********************************************************************************
   * Copyright (c) 2019-2020 TypeFox and others.
   *
   * This program and the accompanying materials are made available under the
   * terms of the Eclipse Public License v. 2.0 which is available at
   * http://www.eclipse.org/legal/epl-2.0.
   *
   * This Source Code may also be made available under the following Secondary
   * Licenses when the conditions for such availability set forth in the Eclipse
   * Public License v. 2.0 are satisfied: GNU General Public License, version 2
   * with the GNU Classpath Exception which is available at
   * https://www.gnu.org/software/classpath/license.html.
   *
   * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
   ********************************************************************************/
  var __extends = (this && this.__extends) || (function () {
      var extendStatics = function (d, b) {
          extendStatics = Object.setPrototypeOf ||
              ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
              function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
          return extendStatics(d, b);
      };
      return function (d, b) {
          extendStatics(d, b);
          function __() { this.constructor = d; }
          d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
      };
  })();
  var __assign = (this && this.__assign) || function () {
      __assign = Object.assign || function(t) {
          for (var s, i = 1, n = arguments.length; i < n; i++) {
              s = arguments[i];
              for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                  t[p] = s[p];
          }
          return t;
      };
      return __assign.apply(this, arguments);
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  var smodel_utils_1 = require("../../base/model/smodel-utils");
  var geometry_1 = require("../../utils/geometry");
  var linear_edge_router_1 = require("./linear-edge-router");
  var model_1 = require("./model");
  var ManhattanEdgeRouter = /** @class */ (function (_super) {
      __extends(ManhattanEdgeRouter, _super);
      function ManhattanEdgeRouter() {
          return _super !== null && _super.apply(this, arguments) || this;
      }
      Object.defineProperty(ManhattanEdgeRouter.prototype, "kind", {
          get: function () {
              return ManhattanEdgeRouter.KIND;
          },
          enumerable: true,
          configurable: true
      });
      ManhattanEdgeRouter.prototype.getOptions = function (edge) {
          return {
              standardDistance: 20,
              minimalPointDistance: 3,
              selfEdgeOffset: 0.25
          };
      };
      ManhattanEdgeRouter.prototype.route = function (edge) {
          if (!edge.source || !edge.target)
              return [];
          var routedCorners = this.createRoutedCorners(edge);
          var sourceRefPoint = routedCorners[0]
              || smodel_utils_1.translatePoint(geometry_1.center(edge.target.bounds), edge.target.parent, edge.parent);
          var sourceAnchor = this.getTranslatedAnchor(edge.source, sourceRefPoint, edge.parent, edge, edge.sourceAnchorCorrection);
          var targetRefPoint = routedCorners[routedCorners.length - 1]
              || smodel_utils_1.translatePoint(geometry_1.center(edge.source.bounds), edge.source.parent, edge.parent);
          var targetAnchor = this.getTranslatedAnchor(edge.target, targetRefPoint, edge.parent, edge, edge.targetAnchorCorrection);
          if (!sourceAnchor || !targetAnchor)
              return [];
          var routedPoints = [];
          routedPoints.push(__assign({ kind: 'source' }, sourceAnchor));
          routedCorners.forEach(function (corner) { return routedPoints.push(corner); });
          routedPoints.push(__assign({ kind: 'target' }, targetAnchor));
          return routedPoints;
      };
      ManhattanEdgeRouter.prototype.createRoutedCorners = function (edge) {
          var sourceAnchors = new linear_edge_router_1.DefaultAnchors(edge.source, edge.parent, 'source');
          var targetAnchors = new linear_edge_router_1.DefaultAnchors(edge.target, edge.parent, 'target');
          if (edge.routingPoints.length > 0) {
              var routingPointsCopy = edge.routingPoints.slice();
              this.cleanupRoutingPoints(edge, routingPointsCopy, false, true);
              if (routingPointsCopy.length > 0)
                  return routingPointsCopy.map(function (routingPoint, index) {
                      return __assign({ kind: 'linear', pointIndex: index }, routingPoint);
                  });
          }
          var options = this.getOptions(edge);
          var corners = this.calculateDefaultCorners(edge, sourceAnchors, targetAnchors, options);
          return corners.map(function (corner) {
              return __assign({ kind: 'linear' }, corner);
          });
      };
      ManhattanEdgeRouter.prototype.createRoutingHandles = function (edge) {
          var routedPoints = this.route(edge);
          this.commitRoute(edge, routedPoints);
          if (routedPoints.length > 0) {
              this.addHandle(edge, 'source', 'routing-point', -2);
              for (var i = 0; i < routedPoints.length - 1; ++i)
                  this.addHandle(edge, 'manhattan-50%', 'volatile-routing-point', i - 1);
              this.addHandle(edge, 'target', 'routing-point', routedPoints.length - 2);
          }
      };
      ManhattanEdgeRouter.prototype.getInnerHandlePosition = function (edge, route, handle) {
          var fraction = this.getFraction(handle.kind);
          if (fraction !== undefined) {
              var _a = this.findRouteSegment(edge, route, handle.pointIndex), start = _a.start, end = _a.end;
              if (start !== undefined && end !== undefined)
                  return geometry_1.linear(start, end, fraction);
          }
          return undefined;
      };
      ManhattanEdgeRouter.prototype.getFraction = function (kind) {
          switch (kind) {
              case 'manhattan-50%': return 0.5;
              default: return undefined;
          }
      };
      ManhattanEdgeRouter.prototype.commitRoute = function (edge, routedPoints) {
          var newRoutingPoints = [];
          for (var i = 1; i < routedPoints.length - 1; ++i)
              newRoutingPoints.push({ x: routedPoints[i].x, y: routedPoints[i].y });
          edge.routingPoints = newRoutingPoints;
      };
      ManhattanEdgeRouter.prototype.applyInnerHandleMoves = function (edge, moves) {
          var _this = this;
          var route = this.route(edge);
          var routingPoints = edge.routingPoints;
          var minimalPointDistance = this.getOptions(edge).minimalPointDistance;
          moves.forEach(function (move) {
              var handle = move.handle;
              var index = handle.pointIndex;
              var correctedX = _this.correctX(routingPoints, index, move.toPosition.x, minimalPointDistance);
              var correctedY = _this.correctY(routingPoints, index, move.toPosition.y, minimalPointDistance);
              switch (handle.kind) {
                  case 'manhattan-50%':
                      if (index < 0) {
                          if (geometry_1.almostEquals(route[0].x, route[1].x))
                              _this.alignX(routingPoints, 0, correctedX);
                          else
                              _this.alignY(routingPoints, 0, correctedY);
                      }
                      else if (index < routingPoints.length - 1) {
                          if (geometry_1.almostEquals(routingPoints[index].x, routingPoints[index + 1].x)) {
                              _this.alignX(routingPoints, index, correctedX);
                              _this.alignX(routingPoints, index + 1, correctedX);
                          }
                          else {
                              _this.alignY(routingPoints, index, correctedY);
                              _this.alignY(routingPoints, index + 1, correctedY);
                          }
                      }
                      else {
                          if (geometry_1.almostEquals(route[route.length - 2].x, route[route.length - 1].x))
                              _this.alignX(routingPoints, routingPoints.length - 1, correctedX);
                          else
                              _this.alignY(routingPoints, routingPoints.length - 1, correctedY);
                      }
                      break;
              }
          });
      };
      ManhattanEdgeRouter.prototype.correctX = function (routingPoints, index, x, minimalPointDistance) {
          if (index > 0 && Math.abs(x - routingPoints[index - 1].x) < minimalPointDistance)
              return routingPoints[index - 1].x;
          else if (index < routingPoints.length - 2 && Math.abs(x - routingPoints[index + 2].x) < minimalPointDistance)
              return routingPoints[index + 2].x;
          else
              return x;
      };
      ManhattanEdgeRouter.prototype.alignX = function (routingPoints, index, x) {
          if (index >= 0 && index < routingPoints.length)
              routingPoints[index] = {
                  x: x,
                  y: routingPoints[index].y
              };
      };
      ManhattanEdgeRouter.prototype.correctY = function (routingPoints, index, y, minimalPointDistance) {
          if (index > 0 && Math.abs(y - routingPoints[index - 1].y) < minimalPointDistance)
              return routingPoints[index - 1].y;
          else if (index < routingPoints.length - 2 && Math.abs(y - routingPoints[index + 2].y) < minimalPointDistance)
              return routingPoints[index + 2].y;
          else
              return y;
      };
      ManhattanEdgeRouter.prototype.alignY = function (routingPoints, index, y) {
          if (index >= 0 && index < routingPoints.length)
              routingPoints[index] = {
                  x: routingPoints[index].x,
                  y: y
              };
      };
      ManhattanEdgeRouter.prototype.cleanupRoutingPoints = function (edge, routingPoints, updateHandles, addRoutingPoints) {
          var sourceAnchors = new linear_edge_router_1.DefaultAnchors(edge.source, edge.parent, "source");
          var targetAnchors = new linear_edge_router_1.DefaultAnchors(edge.target, edge.parent, "target");
          if (this.resetRoutingPointsOnReconnect(edge, routingPoints, updateHandles, sourceAnchors, targetAnchors))
              return;
          // delete leading RPs inside the bounds of the source
          for (var i = 0; i < routingPoints.length; ++i)
              if (geometry_1.includes(sourceAnchors.bounds, routingPoints[i])) {
                  routingPoints.splice(0, 1);
                  if (updateHandles) {
                      this.removeHandle(edge, -1);
                  }
              }
              else {
                  break;
              }
          // delete trailing RPs inside the bounds of the target
          for (var i = routingPoints.length - 1; i >= 0; --i)
              if (geometry_1.includes(targetAnchors.bounds, routingPoints[i])) {
                  routingPoints.splice(i, 1);
                  if (updateHandles) {
                      this.removeHandle(edge, i);
                  }
              }
              else {
                  break;
              }
          if (routingPoints.length >= 2) {
              var options = this.getOptions(edge);
              for (var i = routingPoints.length - 2; i >= 0; --i) {
                  if (geometry_1.manhattanDistance(routingPoints[i], routingPoints[i + 1]) < options.minimalPointDistance) {
                      routingPoints.splice(i, 2);
                      --i;
                      if (updateHandles) {
                          this.removeHandle(edge, i - 1);
                          this.removeHandle(edge, i);
                      }
                  }
              }
          }
          if (addRoutingPoints) {
              this.addAdditionalCorner(edge, routingPoints, sourceAnchors, targetAnchors, updateHandles);
              this.addAdditionalCorner(edge, routingPoints, targetAnchors, sourceAnchors, updateHandles);
              this.manhattanify(edge, routingPoints);
          }
      };
      ManhattanEdgeRouter.prototype.removeHandle = function (edge, pointIndex) {
          var toBeRemoved = [];
          edge.children.forEach(function (child) {
              if (child instanceof model_1.SRoutingHandle) {
                  if (child.pointIndex > pointIndex)
                      --child.pointIndex;
                  else if (child.pointIndex === pointIndex)
                      toBeRemoved.push(child);
              }
          });
          toBeRemoved.forEach(function (child) { return edge.remove(child); });
      };
      ManhattanEdgeRouter.prototype.addAdditionalCorner = function (edge, routingPoints, currentAnchors, otherAnchors, updateHandles) {
          if (routingPoints.length === 0)
              return;
          var refPoint = currentAnchors.kind === 'source' ? routingPoints[0] : routingPoints[routingPoints.length - 1];
          var index = currentAnchors.kind === 'source' ? 0 : routingPoints.length;
          var shiftIndex = index - (currentAnchors.kind === 'source' ? 1 : 0);
          var isHorizontal;
          if (routingPoints.length > 1) {
              isHorizontal = index === 0
                  ? geometry_1.almostEquals(routingPoints[0].x, routingPoints[1].x)
                  : geometry_1.almostEquals(routingPoints[routingPoints.length - 1].x, routingPoints[routingPoints.length - 2].x);
          }
          else {
              var nearestSide = otherAnchors.getNearestSide(refPoint);
              isHorizontal = nearestSide === linear_edge_router_1.Side.TOP || nearestSide === linear_edge_router_1.Side.BOTTOM;
          }
          if (isHorizontal) {
              if (refPoint.y < currentAnchors.get(linear_edge_router_1.Side.TOP).y || refPoint.y > currentAnchors.get(linear_edge_router_1.Side.BOTTOM).y) {
                  var newPoint = { x: currentAnchors.get(linear_edge_router_1.Side.TOP).x, y: refPoint.y };
                  routingPoints.splice(index, 0, newPoint);
                  if (updateHandles) {
                      edge.children.forEach(function (child) {
                          if (child instanceof model_1.SRoutingHandle && child.pointIndex >= shiftIndex)
                              ++child.pointIndex;
                      });
                      this.addHandle(edge, 'manhattan-50%', 'volatile-routing-point', shiftIndex);
                  }
              }
          }
          else {
              if (refPoint.x < currentAnchors.get(linear_edge_router_1.Side.LEFT).x || refPoint.x > currentAnchors.get(linear_edge_router_1.Side.RIGHT).x) {
                  var newPoint = { x: refPoint.x, y: currentAnchors.get(linear_edge_router_1.Side.LEFT).y };
                  routingPoints.splice(index, 0, newPoint);
                  if (updateHandles) {
                      edge.children.forEach(function (child) {
                          if (child instanceof model_1.SRoutingHandle && child.pointIndex >= shiftIndex)
                              ++child.pointIndex;
                      });
                      this.addHandle(edge, 'manhattan-50%', 'volatile-routing-point', shiftIndex);
                  }
              }
          }
      };
      /**
       * Add artificial routing points to keep all angles rectilinear.
       *
       * This makes edge morphing look a lot smoother, where RP positions are interpolated
       * linearly probably resulting in non-rectilinear angles. We don't add handles for
       * these additional RPs.
       */
      ManhattanEdgeRouter.prototype.manhattanify = function (edge, routingPoints) {
          for (var i = 1; i < routingPoints.length; ++i) {
              var isVertical = Math.abs(routingPoints[i - 1].x - routingPoints[i].x) < 1;
              var isHorizontal = Math.abs(routingPoints[i - 1].y - routingPoints[i].y) < 1;
              if (!isVertical && !isHorizontal) {
                  routingPoints.splice(i, 0, {
                      x: routingPoints[i - 1].x,
                      y: routingPoints[i].y
                  });
                  ++i;
              }
          }
      };
      ManhattanEdgeRouter.prototype.calculateDefaultCorners = function (edge, sourceAnchors, targetAnchors, options) {
          var selfEdge = _super.prototype.calculateDefaultCorners.call(this, edge, sourceAnchors, targetAnchors, options);
          if (selfEdge.length > 0)
              return selfEdge;
          var bestAnchors = this.getBestConnectionAnchors(edge, sourceAnchors, targetAnchors, options);
          var sourceSide = bestAnchors.source;
          var targetSide = bestAnchors.target;
          var corners = [];
          var startPoint = sourceAnchors.get(sourceSide);
          var endPoint = targetAnchors.get(targetSide);
          switch (sourceSide) {
              case linear_edge_router_1.Side.RIGHT:
                  switch (targetSide) {
                      case linear_edge_router_1.Side.BOTTOM:
                          corners.push({ x: endPoint.x, y: startPoint.y });
                          break;
                      case linear_edge_router_1.Side.TOP:
                          corners.push({ x: endPoint.x, y: startPoint.y });
                          break;
                      case linear_edge_router_1.Side.RIGHT:
                          corners.push({ x: Math.max(startPoint.x, endPoint.x) + 1.5 * options.standardDistance, y: startPoint.y });
                          corners.push({ x: Math.max(startPoint.x, endPoint.x) + 1.5 * options.standardDistance, y: endPoint.y });
                          break;
                      case linear_edge_router_1.Side.LEFT:
                          if (endPoint.y !== startPoint.y) {
                              corners.push({ x: (startPoint.x + endPoint.x) / 2, y: startPoint.y });
                              corners.push({ x: (startPoint.x + endPoint.x) / 2, y: endPoint.y });
                          }
                          break;
                  }
                  break;
              case linear_edge_router_1.Side.LEFT:
                  switch (targetSide) {
                      case linear_edge_router_1.Side.BOTTOM:
                          corners.push({ x: endPoint.x, y: startPoint.y });
                          break;
                      case linear_edge_router_1.Side.TOP:
                          corners.push({ x: endPoint.x, y: startPoint.y });
                          break;
                      default:
                          endPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
                          if (endPoint.y !== startPoint.y) {
                              corners.push({ x: (startPoint.x + endPoint.x) / 2, y: startPoint.y });
                              corners.push({ x: (startPoint.x + endPoint.x) / 2, y: endPoint.y });
                          }
                          break;
                  }
                  break;
              case linear_edge_router_1.Side.TOP:
                  switch (targetSide) {
                      case linear_edge_router_1.Side.RIGHT:
                          if ((endPoint.x - startPoint.x) > 0) {
                              corners.push({ x: startPoint.x, y: startPoint.y - options.standardDistance });
                              corners.push({ x: endPoint.x + 1.5 * options.standardDistance, y: startPoint.y - options.standardDistance });
                              corners.push({ x: endPoint.x + 1.5 * options.standardDistance, y: endPoint.y });
                          }
                          else {
                              corners.push({ x: startPoint.x, y: endPoint.y });
                          }
                          break;
                      case linear_edge_router_1.Side.LEFT:
                          if ((endPoint.x - startPoint.x) < 0) {
                              corners.push({ x: startPoint.x, y: startPoint.y - options.standardDistance });
                              corners.push({ x: endPoint.x - 1.5 * options.standardDistance, y: startPoint.y - options.standardDistance });
                              corners.push({ x: endPoint.x - 1.5 * options.standardDistance, y: endPoint.y });
                          }
                          else {
                              corners.push({ x: startPoint.x, y: endPoint.y });
                          }
                          break;
                      case linear_edge_router_1.Side.TOP:
                          corners.push({ x: startPoint.x, y: Math.min(startPoint.y, endPoint.y) - 1.5 * options.standardDistance });
                          corners.push({ x: endPoint.x, y: Math.min(startPoint.y, endPoint.y) - 1.5 * options.standardDistance });
                          break;
                      case linear_edge_router_1.Side.BOTTOM:
                          if (endPoint.x !== startPoint.x) {
                              corners.push({ x: startPoint.x, y: (startPoint.y + endPoint.y) / 2 });
                              corners.push({ x: endPoint.x, y: (startPoint.y + endPoint.y) / 2 });
                          }
                          break;
                  }
                  break;
              case linear_edge_router_1.Side.BOTTOM:
                  switch (targetSide) {
                      case linear_edge_router_1.Side.RIGHT:
                          if ((endPoint.x - startPoint.x) > 0) {
                              corners.push({ x: startPoint.x, y: startPoint.y + options.standardDistance });
                              corners.push({ x: endPoint.x + 1.5 * options.standardDistance, y: startPoint.y + options.standardDistance });
                              corners.push({ x: endPoint.x + 1.5 * options.standardDistance, y: endPoint.y });
                          }
                          else {
                              corners.push({ x: startPoint.x, y: endPoint.y });
                          }
                          break;
                      case linear_edge_router_1.Side.LEFT:
                          if ((endPoint.x - startPoint.x) < 0) {
                              corners.push({ x: startPoint.x, y: startPoint.y + options.standardDistance });
                              corners.push({ x: endPoint.x - 1.5 * options.standardDistance, y: startPoint.y + options.standardDistance });
                              corners.push({ x: endPoint.x - 1.5 * options.standardDistance, y: endPoint.y });
                          }
                          else {
                              corners.push({ x: startPoint.x, y: endPoint.y });
                          }
                          break;
                      default:
                          endPoint = targetAnchors.get(linear_edge_router_1.Side.TOP);
                          if (endPoint.x !== startPoint.x) {
                              corners.push({ x: startPoint.x, y: (startPoint.y + endPoint.y) / 2 });
                              corners.push({ x: endPoint.x, y: (startPoint.y + endPoint.y) / 2 });
                          }
                          break;
                  }
                  break;
          }
          return corners;
      };
      ManhattanEdgeRouter.prototype.getBestConnectionAnchors = function (edge, sourceAnchors, targetAnchors, options) {
          // distance is enough
          var sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.RIGHT);
          var targetPoint = targetAnchors.get(linear_edge_router_1.Side.LEFT);
          if ((targetPoint.x - sourcePoint.x) > options.standardDistance)
              return { source: linear_edge_router_1.Side.RIGHT, target: linear_edge_router_1.Side.LEFT };
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.LEFT);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
          if ((sourcePoint.x - targetPoint.x) > options.standardDistance)
              return { source: linear_edge_router_1.Side.LEFT, target: linear_edge_router_1.Side.RIGHT };
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.TOP);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.BOTTOM);
          if ((sourcePoint.y - targetPoint.y) > options.standardDistance)
              return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.BOTTOM };
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.BOTTOM);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.TOP);
          if ((targetPoint.y - sourcePoint.y) > options.standardDistance)
              return { source: linear_edge_router_1.Side.BOTTOM, target: linear_edge_router_1.Side.TOP };
          // One additional point
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.RIGHT);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.TOP);
          if (((targetPoint.x - sourcePoint.x) > 0.5 * options.standardDistance) && ((targetPoint.y - sourcePoint.y) > options.standardDistance))
              return { source: linear_edge_router_1.Side.RIGHT, target: linear_edge_router_1.Side.TOP };
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.BOTTOM);
          if (((targetPoint.x - sourcePoint.x) > 0.5 * options.standardDistance) && ((sourcePoint.y - targetPoint.y) > options.standardDistance))
              return { source: linear_edge_router_1.Side.RIGHT, target: linear_edge_router_1.Side.BOTTOM };
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.LEFT);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.BOTTOM);
          if (((sourcePoint.x - targetPoint.x) > 0.5 * options.standardDistance) && ((sourcePoint.y - targetPoint.y) > options.standardDistance))
              return { source: linear_edge_router_1.Side.LEFT, target: linear_edge_router_1.Side.BOTTOM };
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.TOP);
          if (((sourcePoint.x - targetPoint.x) > 0.5 * options.standardDistance) && ((targetPoint.y - sourcePoint.y) > options.standardDistance))
              return { source: linear_edge_router_1.Side.LEFT, target: linear_edge_router_1.Side.TOP };
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.TOP);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
          if (((sourcePoint.y - targetPoint.y) > 0.5 * options.standardDistance) && ((sourcePoint.x - targetPoint.x) > options.standardDistance))
              return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.RIGHT };
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.LEFT);
          if (((sourcePoint.y - targetPoint.y) > 0.5 * options.standardDistance) && ((targetPoint.x - sourcePoint.x) > options.standardDistance))
              return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.LEFT };
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.BOTTOM);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
          if (((targetPoint.y - sourcePoint.y) > 0.5 * options.standardDistance) && ((sourcePoint.x - targetPoint.x) > options.standardDistance))
              return { source: linear_edge_router_1.Side.BOTTOM, target: linear_edge_router_1.Side.RIGHT };
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.LEFT);
          if (((targetPoint.y - sourcePoint.y) > 0.5 * options.standardDistance) && ((targetPoint.x - sourcePoint.x) > options.standardDistance))
              return { source: linear_edge_router_1.Side.BOTTOM, target: linear_edge_router_1.Side.LEFT };
          // Two points
          // priority NN >> EE >> NE >> NW >> SE >> SW
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.TOP);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.TOP);
          if (!geometry_1.includes(targetAnchors.bounds, sourcePoint) && !geometry_1.includes(sourceAnchors.bounds, targetPoint)) {
              if ((sourcePoint.y - targetPoint.y) < 0) {
                  if (Math.abs(sourcePoint.x - targetPoint.x) > ((sourceAnchors.bounds.width + options.standardDistance) / 2))
                      return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.TOP };
              }
              else {
                  if (Math.abs(sourcePoint.x - targetPoint.x) > (targetAnchors.bounds.width / 2))
                      return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.TOP };
              }
          }
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.RIGHT);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
          if (!geometry_1.includes(targetAnchors.bounds, sourcePoint) && !geometry_1.includes(sourceAnchors.bounds, targetPoint)) {
              if ((sourcePoint.x - targetPoint.x) > 0) {
                  if (Math.abs(sourcePoint.y - targetPoint.y) > ((sourceAnchors.bounds.height + options.standardDistance) / 2))
                      return { source: linear_edge_router_1.Side.RIGHT, target: linear_edge_router_1.Side.RIGHT };
              }
              else if (Math.abs(sourcePoint.y - targetPoint.y) > (targetAnchors.bounds.height / 2))
                  return { source: linear_edge_router_1.Side.RIGHT, target: linear_edge_router_1.Side.RIGHT };
          }
          // Secondly, judge NE NW is available
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.TOP);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
          if (!geometry_1.includes(targetAnchors.bounds, sourcePoint) && !geometry_1.includes(sourceAnchors.bounds, targetPoint))
              return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.RIGHT };
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.LEFT);
          if (!geometry_1.includes(targetAnchors.bounds, sourcePoint) && !geometry_1.includes(sourceAnchors.bounds, targetPoint))
              return { source: linear_edge_router_1.Side.TOP, target: linear_edge_router_1.Side.LEFT };
          // Finally, judge SE SW is available
          sourcePoint = sourceAnchors.get(linear_edge_router_1.Side.BOTTOM);
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.RIGHT);
          if (!geometry_1.includes(targetAnchors.bounds, sourcePoint) && !geometry_1.includes(sourceAnchors.bounds, targetPoint))
              return { source: linear_edge_router_1.Side.BOTTOM, target: linear_edge_router_1.Side.RIGHT };
          targetPoint = targetAnchors.get(linear_edge_router_1.Side.LEFT);
          if (!geometry_1.includes(targetAnchors.bounds, sourcePoint) && !geometry_1.includes(sourceAnchors.bounds, targetPoint))
              return { source: linear_edge_router_1.Side.BOTTOM, target: linear_edge_router_1.Side.LEFT };
          // Only to return to the
          return { source: linear_edge_router_1.Side.RIGHT, target: linear_edge_router_1.Side.BOTTOM };
      };
      ManhattanEdgeRouter.KIND = 'manhattan';
      return ManhattanEdgeRouter;
  }(linear_edge_router_1.LinearEdgeRouter));
  exports.ManhattanEdgeRouter = ManhattanEdgeRouter;
  //# sourceMappingURL=manhattan-edge-router.js.map