/** * Created by Alex on 3/20/2015. */ import EdgeBase from './EdgeBase' class BezierEdgeBase extends EdgeBase { constructor(options, body, labelModule) { super(options, body, labelModule); } /** * This function uses binary search to look for the point where the bezier curve crosses the border of the node. * * @param nearNode * @param ctx * @param viaNode * @param nearNode * @param ctx * @param viaNode * @param nearNode * @param ctx * @param viaNode */ _findBorderPositionBezier(nearNode, ctx, viaNode = this._getViaCoordinates()) { var maxIterations = 10; var iteration = 0; var low = 0; var high = 1; var pos, angle, distanceToBorder, distanceToPoint, difference; var threshold = 0.2; var node = this.to; var from = false; if (nearNode.id === this.from.id) { node = this.from; from = true; } while (low <= high && iteration < maxIterations) { var middle = (low + high) * 0.5; pos = this.getPoint(middle, viaNode); angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); distanceToBorder = node.distanceToBorder(ctx, angle); distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2)); difference = distanceToBorder - distanceToPoint; if (Math.abs(difference) < threshold) { break; // found } else if (difference < 0) { // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node. if (from === false) { low = middle; } else { high = middle; } } else { if (from === false) { high = middle; } else { low = middle; } } iteration++; } pos.t = middle; return pos; } /** * Calculate the distance between a point (x3,y3) and a line segment from * (x1,y1) to (x2,y2). * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment * @param {number} x1 * @param {number} y1 * @param {number} x2 * @param {number} y2 * @param {number} x3 * @param {number} y3 * @private */ _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) { // x3,y3 is the point let xVia, yVia; xVia = via.x; yVia = via.y; let minDistance = 1e9; let distance; let i, t, x, y; let lastX = x1; let lastY = y1; for (i = 1; i < 10; i++) { t = 0.1 * i; x = Math.pow(1 - t, 2) * x1 + (2 * t * (1 - t)) * xVia + Math.pow(t, 2) * x2; y = Math.pow(1 - t, 2) * y1 + (2 * t * (1 - t)) * yVia + Math.pow(t, 2) * y2; if (i > 0) { distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3); minDistance = distance < minDistance ? distance : minDistance; } lastX = x; lastY = y; } return minDistance; } } export default BezierEdgeBase;