Skip to content

Commit

Permalink
feat(routers.RightAngle): improve discussed issues
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinKanera committed Jul 27, 2023
1 parent 005ee34 commit 7c54e51
Showing 1 changed file with 139 additions and 45 deletions.
184 changes: 139 additions & 45 deletions src/routers/rightAngle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,50 @@ const OPPOSITE_DIRECTIONS = {
[Directions.BOTTOM]: Directions.TOP
};

const AREA_CROSSING_DIRECTIONS = {
90: Directions.TOP,
180: Directions.RIGHT,
270: Directions.BOTTOM,
0: Directions.LEFT
};

function resolveSides(source, target) {
const { point: sourcePoint, x0: sx0, y0: sy0, view: sourceView, bbox: sourceBBox, direction: sourceDirection } = source;
const { point: targetPoint, x0: tx0, y0: ty0, view: targetView, bbox: targetBBox, direction: targetDirection } = target;

let sourceSide;

if (!sourceView) {
const sourceLinkAnchorBBox = new g.Rect(sx0, sy0, 0, 0);
sourceSide = DEFINED_DIRECTIONS.includes(sourceDirection) ? sourceDirection : sourceLinkAnchorBBox.sideNearestToPoint(targetPoint);
} else if (sourceView.model.isLink()) {
sourceSide = getDirectionForLinkConnection(targetPoint, sourcePoint, sourceView);
} else if (sourceDirection === Directions.ANCHOR_SIDE) {
sourceSide = sourceBBox.sideNearestToPoint(sourcePoint);
} else if (sourceDirection === Directions.MAGNET_SIDE) {
sourceSide = sourceView.model.getBBox().sideNearestToPoint(sourcePoint);
} else {
sourceSide = sourceDirection;
}

let targetSide;

if (!targetView) {
const targetLinkAnchorBBox = new g.Rect(tx0, ty0, 0, 0);
targetSide = DEFINED_DIRECTIONS.includes(targetDirection) ? targetDirection : targetLinkAnchorBBox.sideNearestToPoint(sourcePoint);
} else if (targetView.model.isLink()) {
targetSide = getDirectionForLinkConnection(sourcePoint, targetPoint, targetView);
} else if (targetDirection === Directions.ANCHOR_SIDE) {
targetSide = targetBBox.sideNearestToPoint(targetPoint);
} else if (targetDirection === Directions.MAGNET_SIDE) {
targetSide = targetView.model.getBBox().sideNearestToPoint(targetPoint);
} else {
targetSide = targetDirection;
}

return [sourceSide, targetSide];
}

function getDirectionForLinkConnection(linkOrigin, connectionPoint, linkView) {
const tangent = linkView.getTangentAtLength(linkView.getClosestPointLength(connectionPoint));
const roundedAngle = Math.round(tangent.angle() / 90) * 90;
Expand Down Expand Up @@ -56,8 +100,7 @@ function pointDataFromAnchor(view, point, bbox, direction, isPort, fallBackAncho
bbox,
width,
height,
direction,
isVertex: false
direction
};
}

Expand All @@ -77,8 +120,8 @@ function pointDataFromVertex({ x, y }, nextBBox) {
}

function routeBetweenPoints(source, target, margin) {
const { point: sourcePoint, x0: sx0, y0: sy0, view: sourceView, bbox: sourceBBox, width: sourceWidth, height: sourceHeight, direction: sourceDirection } = source;
const { point: targetPoint, x0: tx0, y0: ty0, view: targetView, bbox: targetBBox, width: targetWidth, height: targetHeight, direction: targetDirection } = target;
const { point: sourcePoint, x0: sx0, y0: sy0, view: sourceView, width: sourceWidth, height: sourceHeight } = source;
const { point: targetPoint, x0: tx0, y0: ty0, view: targetView, width: targetWidth, height: targetHeight } = target;

const tx1 = tx0 + targetWidth;
const ty1 = ty0 + targetHeight;
Expand All @@ -102,20 +145,7 @@ function routeBetweenPoints(source, target, margin) {

const sourceOutsidePoint = sourcePoint.clone();

let sourceSide;

if (!sourceView) {
const sourceLinkAnchorBBox = new g.Rect(sx0, sy0, 0, 0);
sourceSide = DEFINED_DIRECTIONS.includes(sourceDirection) ? sourceDirection : sourceLinkAnchorBBox.sideNearestToPoint(targetPoint);
} else if (sourceView.model.isLink()) {
sourceSide = getDirectionForLinkConnection(targetPoint, sourcePoint, sourceView);
} else if (sourceDirection === Directions.ANCHOR_SIDE) {
sourceSide = sourceBBox.sideNearestToPoint(sourcePoint);
} else if (sourceDirection === Directions.MAGNET_SIDE) {
sourceSide = sourceView.model.getBBox().sideNearestToPoint(sourcePoint);
} else {
sourceSide = sourceDirection;
}
const [sourceSide, targetSide] = resolveSides(source, target);

switch (sourceSide) {
case 'left':
Expand All @@ -134,21 +164,6 @@ function routeBetweenPoints(source, target, margin) {

const targetOutsidePoint = targetPoint.clone();

let targetSide;

if (!targetView) {
const targetLinkAnchorBBox = new g.Rect(tx0, ty0, 0, 0);
targetSide = DEFINED_DIRECTIONS.includes(targetDirection) ? targetDirection : targetLinkAnchorBBox.sideNearestToPoint(sourcePoint);
} else if (targetView.model.isLink()) {
targetSide = getDirectionForLinkConnection(sourcePoint, targetPoint, targetView);
} else if (targetDirection === Directions.ANCHOR_SIDE) {
targetSide = targetBBox.sideNearestToPoint(targetPoint);
} else if (targetDirection === Directions.MAGNET_SIDE) {
targetSide = targetView.model.getBBox().sideNearestToPoint(targetPoint);
} else {
targetSide = targetDirection;
}

switch (targetSide) {
case 'left':
targetOutsidePoint.x = tmx0;
Expand All @@ -173,6 +188,33 @@ function routeBetweenPoints(source, target, margin) {
const middleOfVerticalSides = (scx < tcx ? (sx1 + tx0) : (tx1 + sx0)) / 2;
const middleOfHorizontalSides = (scy < tcy ? (sy1 + ty0) : (ty1 + sy0)) / 2;

if (!(isSourceEl && isTargetEl) && (sox === tox || soy === toy)) {
const line = new g.Line(sourcePoint, targetPoint);
const angle = line.angle();

if (isSourceEl && AREA_CROSSING_DIRECTIONS[angle] !== sourceSide) {
const result = [{ x: sox, y: soy }];

// there can be a rare case where the source and target are the same point
// and that can cause trouble
if (sox !== tox || soy !== toy) {
result.push({ x: tox, y: toy });
}

return result;
} else if (isTargetEl && OPPOSITE_DIRECTIONS[AREA_CROSSING_DIRECTIONS[angle]] !== targetSide) {
const result = [{ x: tox, y: toy }];

// there can be a rare case where the source and target are the same point
// and that can cause trouble
if (sox !== tox || soy !== toy) {
result.unshift({ x: sox, y: soy });
}

return result;
}
}

if (sourceSide === 'left' && targetSide === 'right') {
if (smx0 <= tmx1) {
let y = middleOfHorizontalSides;
Expand Down Expand Up @@ -306,7 +348,7 @@ function routeBetweenPoints(source, target, margin) {
{ x: tox, y: y1 }
];
} else if (sourceSide === 'bottom' && targetSide === 'bottom') {
if (tx0 >= sox + sourceMargin || tx1 <= sox - sourceMargin) {
if ((tx0 >= sox + sourceMargin || tx1 <= sox - sourceMargin) && (isTargetEl || isSourceEl)) {
return [
{ x: sox, y: Math.max(soy, toy) },
{ x: tox, y: Math.max(soy, toy) }
Expand Down Expand Up @@ -362,12 +404,27 @@ function routeBetweenPoints(source, target, margin) {
}
}

return [
{ x: x2, y: soy },
const result = [
{ x: x2, y },
{ x: x1, y },
{ x: x1, y: toy }
];

// x1 and x2 are equal - redundant point
if (x1 === x2) {
result.pop();
}

// There are cases where 2 points are enough to draw the route and
// additional points would cause problems
if (soy !== y) {
result.unshift({ x: x2, y: soy });
}

if (toy !== y) {
result.push({ x: x1, y: toy });
}

return result;
} else if (sourceSide === 'right' && targetSide === 'right') {
let y;
let x1 = Math.max((sx0 + tx1) / 2, tox);
Expand All @@ -387,12 +444,27 @@ function routeBetweenPoints(source, target, margin) {
}
}

return [
{ x: x2, y: soy },
{ x: x2, y },
{ x: x1, y },
{ x: x1, y: toy }
];
const result = [];

// Add points to the result array based on the conditions
if (x1 !== x2) {
result.push({ x: x2, y });
result.push({ x: x1, y });
} else {
result.push({ x: x1, y });
}

// There are cases where 2 points are enough to draw the route and
// additional points would cause problems
if (soy !== y) {
result.unshift({ x: x2, y: soy });
}

if (toy !== y) {
result.push({ x: x1, y: toy });
}

return result;
} else if (sourceSide === 'top' && targetSide === 'right') {
if (soy > toy) {
if (sox < tox) {
Expand Down Expand Up @@ -691,7 +763,7 @@ function rightAngleRouter(vertices, opt, linkView) {

const isTargetPort = !!linkView.model.target().port;
const targetPoint = pointDataFromAnchor(linkView.targetView, linkView.targetAnchor, linkView.targetBBox, targetDirection, isTargetPort, linkView.targetAnchor);
// // First point is always the source anchor point

let resultVertices = [];
let source = sourcePoint;

Expand All @@ -706,13 +778,35 @@ function rightAngleRouter(vertices, opt, linkView) {
const nextBBox = new g.Rect(next.x, next.y, 0, 0);
const target = pointDataFromVertex(current, nextBBox);

if (new g.Point(current).equals(resultVertices[resultVertices.length - 1])) {
target.direction = OPPOSITE_DIRECTIONS[target.direction];
source = target;
continue;
}

resultVertices.push(...routeBetweenPoints(source, target, margin));

target.direction = OPPOSITE_DIRECTIONS[target.direction];
source = target;
}

resultVertices.push(...routeBetweenPoints(source, targetPoint, margin));
const targetPointRoute = routeBetweenPoints(source, targetPoint, margin);

if (new g.Point(targetPointRoute[0]).equals(resultVertices[resultVertices.length - 1])) resultVertices.push(...targetPointRoute.slice(1));
else resultVertices.push(...targetPointRoute);

// Clean up - remove the first and the last point if they are the same as
// the source and target points because they would be redundant

if (sourcePoint.point.equals(resultVertices[0])) {
resultVertices.shift();
}

const lastIndex = resultVertices.length - 1;

if (targetPoint.point.equals(resultVertices[lastIndex])) {
resultVertices.pop();
}

return resultVertices;
}
Expand Down

0 comments on commit 7c54e51

Please sign in to comment.