blob: 913a8fb56f315227d93b132d5ca17d0174f9bd5f [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.draw2d.ui.graph;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.graph.DirectedGraph;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.EdgeList;
import org.eclipse.draw2d.graph.Node;
/**
* Assigns the locations to edges end points as well as lays out border nodes
*
* @author aboyko
* @since 2.1
*/
class EdgeEndPointsAssignment {
private DirectedGraph graph;
public EdgeEndPointsAssignment(DirectedGraph g) {
this.graph = g;
}
void assignEdgesEndPoints() {
for (int i = 0; i < graph.edges.size(); i++) {
Edge e = graph.edges.getEdge(i);
e.start = null;
e.end = null;
}
Collections.sort(graph.nodes, new Comparator<Node>() {
public int compare(Node arg0, Node arg1) {
return arg0.width - arg1.width;
}
});
for (int i = 0; i < graph.nodes.size(); i++) {
Node node = graph.nodes.getNode(i);
assignEndPointsForEdgesFromNode(node);
}
}
private void assignEndPointsForEdgesFromNode(Node node) {
EdgeList incoming = new EdgeList(), outgoing = new EdgeList();
List<BorderNode> specialBorderNodes = new ArrayList<BorderNode>();
if (node instanceof ConstantSizeNode) {
initEdgesSets((ConstantSizeNode)node, incoming, outgoing, specialBorderNodes);
} else {
incoming = node.incoming;
outgoing = node.outgoing;
}
if (node instanceof ConstantSizeNode && ((ConstantSizeNode)node).minIncomingPadding > 0) {
assignEdgesEndPoints(incoming, (ConstantSizeNode) node, true);
} else {
for (int i = 0; i < incoming.size(); i++) {
setEndPoint(incoming.getEdge(i), new Point(node.x + node.getOffsetIncoming(), node.y));
}
}
if (node instanceof ConstantSizeNode && ((ConstantSizeNode)node).minOutgoingPadding > 0) {
assignEdgesEndPoints(outgoing, (ConstantSizeNode) node, false);
} else {
for (int i = 0; i < outgoing.size(); i++) {
setStartPoint(outgoing.getEdge(i), new Point(node.x + node.getOffsetOutgoing(), node.y + node.height));
}
}
if (node instanceof ConstantSizeNode) {
assignEndPointsForJointEdgeWithIncomingAndOutgoingEdges((ConstantSizeNode)node, specialBorderNodes);
}
}
private void initEdgesSets(ConstantSizeNode n, EdgeList incoming, EdgeList outgoing, List<BorderNode> specialBorderNodes) {
for (int i = 0; i < n.outgoing.size(); i++) {
Edge e = n.outgoing.getEdge(i);
if (e instanceof ConstrainedEdge) {
ConstrainedEdge ce = (ConstrainedEdge) e;
if (ce.sourceConstraint != null) {
continue;
}
}
outgoing.add(e);
}
for (int i = 0; i < n.incoming.size(); i++) {
Edge e = n.incoming.getEdge(i);
if (e instanceof ConstrainedEdge) {
ConstrainedEdge ce = (ConstrainedEdge) e;
if (ce.targetConstraint != null) {
continue;
}
}
incoming.add(e);
}
for (Iterator<BorderNode> itr = n.borderNodes.iterator(); itr.hasNext();) {
BorderNode borderNode = itr.next();
if (!(borderNode.incomingJointEdges.edges.isEmpty() ^ borderNode.outgoingJointEdges.edges.isEmpty())) {
specialBorderNodes.add(borderNode);
} else if (borderNode.incomingJointEdges.edges.isEmpty()) {
outgoing.add(borderNode.outgoingJointEdges);
} else {
incoming.add(borderNode.incomingJointEdges);
}
}
Collections.sort(incoming, new Comparator<Edge>() {
public int compare(Edge e1, Edge e2) {
return GraphUtilities.getIncomingEdgeBendpointX(e1, graph) - GraphUtilities.getIncomingEdgeBendpointX(e2, graph);
}
});
Collections.sort(outgoing, new Comparator<Edge>() {
public int compare(Edge e1, Edge e2) {
return GraphUtilities.getOutogingEdgeBendpointX(e1, graph) - GraphUtilities.getOutogingEdgeBendpointX(e2, graph);
}
});
}
private void assignEdgesEndPoints(EdgeList edges, ConstantSizeNode n, boolean end) {
int leftIndex;
int rightIndex;
int padding = end ? n.minIncomingPadding : n.minOutgoingPadding;
int leftX = n.x;
int rightX = n.x + n.width;
int leftBendpointX = 0;
int rightBendpointX = 0;
for (leftIndex = 0; leftIndex < edges.size(); leftIndex++) {
Edge e = edges.getEdge(leftIndex);
leftBendpointX = end ? GraphUtilities.getIncomingEdgeBendpointX(e, graph) : GraphUtilities.getOutogingEdgeBendpointX(e, graph);
if (leftX < leftBendpointX && leftBendpointX < rightX && (float)(leftBendpointX - leftX)/(leftIndex + 1) >= padding) {
break;
}
}
for (rightIndex = edges.size() - 1; rightIndex >= leftIndex; rightIndex--) {
Edge e = edges.getEdge(rightIndex);
rightBendpointX = end ? GraphUtilities.getIncomingEdgeBendpointX(e, graph) : GraphUtilities.getOutogingEdgeBendpointX(e, graph);
if (leftX < rightBendpointX && rightBendpointX < rightX && (float)(rightX - rightBendpointX)/(edges.size() - rightIndex) >= padding) {
break;
}
}
int y = end ? n.y : n.y + n.height;
if (rightIndex >= leftIndex) {
uniformlyPadEdges(edges, 0, leftIndex, new Point(leftX, y), new Point(leftBendpointX, y), end);
uniformlyPadEdges(edges, rightIndex + 1, edges.size(), new Point(rightBendpointX, y), new Point(rightX, y), end);
makeStraight(edges, leftIndex, rightIndex + 1, end);
} else {
uniformlyPadEdges(edges, 0, edges.size(), new Point(leftX, y), new Point(rightX, y), end);
}
}
private void uniformlyPadEdges(List edges, int startIndex, int endIndex, Point startPoint, Point endPoint, boolean end) {
Dimension diff = endPoint.getDifference(startPoint);
int numPieces = endIndex - startIndex + 1;
for (int i = startIndex; i < endIndex; i++) {
Edge e = (Edge) edges.get(i);
float coefficient = (float) (i - startIndex + 1) / numPieces;
Point p = startPoint.getCopy().translate(diff.getCopy().scale(coefficient));
if (end) {
setEndPoint(e, p);
} else {
setStartPoint(e, p);
}
}
}
private void makeStraight(EdgeList edges, int startIndex, int endIndex, boolean end) {
for (int i = startIndex; i < endIndex; i++) {
Edge e = edges.getEdge(i);
int y = end ? e.target.y : e.source.y + e.source.height;
if (e instanceof ConstrainedEdge) {
ConstrainedEdge ce = (ConstrainedEdge) e;
if (end && ce.targetConstraint != null) {
y = ce.targetConstraint.y;
} else if (!end && ce.sourceConstraint != null) {
y = ce.sourceConstraint.y + ce.sourceConstraint.height;
}
}
if (end) {
setEndPoint(e, new Point(GraphUtilities.getIncomingEdgeBendpointX(e, graph), y));
} else {
setStartPoint(e, new Point(GraphUtilities.getOutogingEdgeBendpointX(e, graph), y));
}
}
}
private void setStartPoint(Edge e, Point p) {
if (e instanceof JointEdges) {
JointEdges je = (JointEdges) e;
je.getJoint().setPoint(p);
assignEndPointsForEdgesFromBorderNode(je.getJoint());
} else {
if (p == null) {
if (e instanceof ConstrainedEdge && ((ConstrainedEdge) e).sourceConstraint != null) {
p = ((ConstrainedEdge) e).sourceConstraint.getEdgesDefaultEndPoint();
} else {
p = new Point(e.source.x + e.source.getOffsetOutgoing(), e.source.y + e.source.height);
}
}
e.start = p;
}
}
private void setEndPoint(Edge e, Point p) {
if (e instanceof JointEdges) {
JointEdges je = (JointEdges) e;
je.getJoint().setPoint(p);
assignEndPointsForEdgesFromBorderNode(je.getJoint());
} else {
if (p == null) {
if (e instanceof ConstrainedEdge && ((ConstrainedEdge) e).targetConstraint != null) {
p = ((ConstrainedEdge) e).targetConstraint.getEdgesDefaultEndPoint();
} else {
p = new Point(e.target.x + e.target.getOffsetIncoming(), e.target.y);
}
}
e.end = p;
}
}
private void assignEndPointsForJointEdgeWithIncomingAndOutgoingEdges(ConstantSizeNode node, List<BorderNode> specialBorderNodes) {
Collections.sort(specialBorderNodes, new Comparator<BorderNode>() {
public int compare(BorderNode bn1, BorderNode bn2) {
return bn1.incomingJointEdges.edges.size() + bn1.outgoingJointEdges.edges.size() - bn2.incomingJointEdges.edges.size() - bn2.outgoingJointEdges.edges.size();
}
});
List<BorderNode> leftSideBorderNodes = new ArrayList<BorderNode>(specialBorderNodes.size() / 2 + 1);
List<BorderNode> rightSideBorderNodes = new ArrayList<BorderNode>(specialBorderNodes.size() / 2 + 1);
for (Iterator<BorderNode> itr = specialBorderNodes.iterator(); itr.hasNext();) {
leftSideBorderNodes.add(itr.next());
itr.remove();
if (itr.hasNext()) {
rightSideBorderNodes.add(itr.next());
itr.remove();
}
}
Collections.sort(leftSideBorderNodes, new Comparator<BorderNode>() {
public int compare(BorderNode bn1, BorderNode bn2) {
return bn1.outgoingJointEdges.edges.size() - bn1.incomingJointEdges.edges.size() - (bn2.outgoingJointEdges.edges.size() - bn2.incomingJointEdges.edges.size());
}
});
Collections.sort(rightSideBorderNodes, new Comparator<BorderNode>() {
public int compare(BorderNode bn1, BorderNode bn2) {
return bn1.outgoingJointEdges.edges.size() - bn1.incomingJointEdges.edges.size() - (bn2.outgoingJointEdges.edges.size() - bn2.incomingJointEdges.edges.size());
}
});
uniformlyPadBorderNodes(leftSideBorderNodes, 0, leftSideBorderNodes.size(), new Point(node.x, node.y), new Point(node.x, node.y + node.height));
uniformlyPadBorderNodes(rightSideBorderNodes, 0, rightSideBorderNodes.size(), new Point(node.x + node.width, node.y), new Point(node.x + node.width, node.y + node.height));
for (Iterator<BorderNode> itr = leftSideBorderNodes.iterator(); itr.hasNext();) {
BorderNode bn = itr.next();
if (!bn.incomingJointEdges.edges.isEmpty() || !bn.outgoingJointEdges.edges.isEmpty()) {
assignEndPointsForEdgesFromBorderNode(bn);
}
}
for (Iterator<BorderNode> itr = rightSideBorderNodes.iterator(); itr.hasNext();) {
BorderNode bn = itr.next();
if (!bn.incomingJointEdges.edges.isEmpty() || !bn.outgoingJointEdges.edges.isEmpty()) {
assignEndPointsForEdgesFromBorderNode(bn);
}
}
}
private void uniformlyPadBorderNodes(List<BorderNode> borderNodes, int startIndex, int endIndex, Point startPoint, Point endPoint) {
Dimension diff = endPoint.getDifference(startPoint);
int numPieces = endIndex - startIndex + 1;
for (int i = startIndex; i < endIndex; i++) {
float coefficient = (float) (i - startIndex + 1) / numPieces;
Point p = startPoint.getCopy().translate(diff.getCopy().scale(coefficient));
borderNodes.get(i).setPoint(p);
}
}
private void assignEndPointsForEdgesFromBorderNode(BorderNode node) {
Collections.sort(node.incomingJointEdges.edges, new Comparator<Edge>() {
public int compare(Edge e1, Edge e2) {
return GraphUtilities.getIncomingEdgeBendpointX(e1, graph) - GraphUtilities.getIncomingEdgeBendpointX(e2, graph); }
});
Collections.sort(node.outgoingJointEdges.edges, new Comparator<Edge>() {
public int compare(Edge e1, Edge e2) {
return GraphUtilities.getOutogingEdgeBendpointX(e1, graph) - GraphUtilities.getOutogingEdgeBendpointX(e2, graph); }
});
if (node.minIncomingPadding > 0 || node.minOutgoingPadding > 0) {
if (node.position == PositionConstants.NORTH) {
assignEdgesEndPoints(node.incomingJointEdges.edges, node, true);
} else if (node.position == PositionConstants.SOUTH) {
assignEdgesEndPoints(node.outgoingJointEdges.edges, node, false);
} else {
Point incomingStartPt, incomingEndPt, outgoingStartPt, outgoingEndPt;
if (node.position == PositionConstants.WEST) {
incomingStartPt = new Point(node.x, node.y + (node.incomingJointEdges.edges.size() + 1) * node.height / (node.incomingJointEdges.edges.size() + node.outgoingJointEdges.edges.size() + 1));
incomingEndPt = new Point(node.x, node.y);
outgoingStartPt = new Point(node.x, node.y + node.incomingJointEdges.edges.size() * node.height / (node.incomingJointEdges.edges.size() + node.outgoingJointEdges.edges.size() + 1));
outgoingEndPt = new Point(node.x, node.y + node.height);
} else {
incomingStartPt = new Point(node.x + node.width, node.y);
incomingEndPt = new Point(node.x + node.width, node.y + (node.incomingJointEdges.edges.size() + 1) * node.height / (node.incomingJointEdges.edges.size() + node.outgoingJointEdges.edges.size() + 1));
outgoingStartPt = new Point(node.x + node.width, node.y + node.height);
outgoingEndPt = new Point(node.x + node.width, node.y + node.incomingJointEdges.edges.size() * node.height / (node.incomingJointEdges.edges.size() + node.outgoingJointEdges.edges.size() + 1));
}
uniformlyPadEdges(node.incomingJointEdges.edges, 0, node.incomingJointEdges.edges.size(), incomingStartPt, incomingEndPt, true);
uniformlyPadEdges(node.outgoingJointEdges.edges, 0, node.outgoingJointEdges.edges.size(), outgoingStartPt, outgoingEndPt, false);
}
} else {
Point defaultPt = node.getEdgesDefaultEndPoint();
for (int i = 0; i < node.incomingJointEdges.edges.size(); i++) {
setEndPoint(node.incomingJointEdges.edges.getEdge(i), defaultPt);
}
for (int i = 0; i < node.outgoingJointEdges.edges.size(); i++) {
setStartPoint(node.outgoingJointEdges.edges.getEdge(i), defaultPt);
}
}
}
}