use of org.eclipse.elk.graph.ElkConnectableShape in project sirius-components by eclipse-sirius.
the class ELKDiagramConverter method convert.
@Override
public ELKConvertedDiagram convert(Diagram diagram) {
Diagram initializedDiagram = this.initializeDiagram(diagram);
ElkNode elkDiagram = this.convertDiagram(initializedDiagram);
Map<String, ElkGraphElement> id2ElkGraphElements = new HashMap<>();
Map<String, ElkConnectableShape> connectableShapeIndex = new LinkedHashMap<>();
initializedDiagram.getNodes().stream().forEach(node -> this.convertNode(node, elkDiagram, connectableShapeIndex, id2ElkGraphElements));
initializedDiagram.getEdges().stream().forEach(edge -> this.convertEdge(edge, elkDiagram, connectableShapeIndex, id2ElkGraphElements));
return new ELKConvertedDiagram(elkDiagram, id2ElkGraphElements);
}
use of org.eclipse.elk.graph.ElkConnectableShape in project elk by eclipse.
the class GmfDiagramLayoutConnector method processConnections.
/**
* Creates new edges and takes care of the labels for each connection identified in the
* {@code buildLayoutGraphRecursively} method.
*
* @param mapping
* the layout mapping
*/
protected void processConnections(final LayoutMapping mapping) {
Map<EReference, ElkEdge> reference2EdgeMap = new HashMap<>();
for (ConnectionEditPart connection : mapping.getProperty(CONNECTIONS)) {
boolean isOppositeEdge = false;
Optional<EdgeLabelPlacement> edgeLabelPlacement = Optional.empty();
ElkEdge edge;
// Check whether the edge belongs to an Ecore reference, which may have opposites.
// This is required for the layout of Ecore diagrams, since the bend points of
// opposite references are kept synchronized by the editor.
EObject modelObject = connection.getNotationView().getElement();
if (modelObject instanceof EReference) {
EReference reference = (EReference) modelObject;
edge = reference2EdgeMap.get(reference.getEOpposite());
if (edge != null) {
edgeLabelPlacement = Optional.of(EdgeLabelPlacement.TAIL);
isOppositeEdge = true;
} else {
edge = ElkGraphUtil.createEdge(null);
reference2EdgeMap.put(reference, edge);
}
} else {
edge = ElkGraphUtil.createEdge(null);
}
BiMap<Object, ElkGraphElement> inverseGraphMap = mapping.getGraphMap().inverse();
// find a proper source node and source port
ElkGraphElement sourceElem;
EditPart sourceObj = connection.getSource();
if (sourceObj instanceof ConnectionEditPart) {
sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getSource());
if (sourceElem == null) {
sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getTarget());
}
} else {
sourceElem = inverseGraphMap.get(sourceObj);
}
ElkConnectableShape sourceShape = null;
ElkPort sourcePort = null;
ElkNode sourceNode = null;
if (sourceElem instanceof ElkNode) {
sourceNode = (ElkNode) sourceElem;
sourceShape = sourceNode;
} else if (sourceElem instanceof ElkPort) {
sourcePort = (ElkPort) sourceElem;
sourceNode = sourcePort.getParent();
sourceShape = sourcePort;
} else {
continue;
}
// find a proper target node and target port
ElkGraphElement targetElem;
EditPart targetObj = connection.getTarget();
if (targetObj instanceof ConnectionEditPart) {
targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getTarget());
if (targetElem == null) {
targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getSource());
}
} else {
targetElem = inverseGraphMap.get(targetObj);
}
ElkConnectableShape targetShape = null;
ElkNode targetNode = null;
ElkPort targetPort = null;
if (targetElem instanceof ElkNode) {
targetNode = (ElkNode) targetElem;
targetShape = targetNode;
} else if (targetElem instanceof ElkPort) {
targetPort = (ElkPort) targetElem;
targetNode = targetPort.getParent();
targetShape = targetPort;
} else {
continue;
}
// calculate offset for edge and label coordinates
ElkNode edgeContainment = ElkGraphUtil.findLowestCommonAncestor(sourceNode, targetNode);
KVector offset = new KVector();
ElkUtil.toAbsolute(offset, edgeContainment);
if (!isOppositeEdge) {
// set source and target
edge.getSources().add(sourceShape);
edge.getTargets().add(targetShape);
// now that source and target are set, put the edge into the graph
edgeContainment.getContainedEdges().add(edge);
mapping.getGraphMap().put(edge, connection);
// store the current coordinates of the edge
setEdgeLayout(edge, connection, offset);
}
// process edge labels
processEdgeLabels(mapping, connection, edge, edgeLabelPlacement, offset);
}
}
use of org.eclipse.elk.graph.ElkConnectableShape in project elk by eclipse.
the class RecursiveGraphLayoutEngine method postProcessInsideSelfLoops.
/**
* Post-processes self loops routed inside by offsetting their coordinates by the coordinates of
* their parent node. The post processing is necessary since the self loop coordinates are
* relative to their parent node's upper left corner since, at that point, the parent node's
* final coordinates are not determined yet.
*
* @param insideSelfLoops
* list of inside self loops to post-process.
*/
protected void postProcessInsideSelfLoops(final List<ElkEdge> insideSelfLoops) {
for (final ElkEdge selfLoop : insideSelfLoops) {
// MIGRATE Adapt to hyperedges and make error-safe
final ElkConnectableShape node = ElkGraphUtil.connectableShapeToNode(selfLoop.getSources().get(0));
final double xOffset = node.getX();
final double yOffset = node.getY();
// Offset the edge coordinates by the node's position
// MIGRATE Adapt to hyperedges. Also, what about multiple edge sections?
ElkEdgeSection section = selfLoop.getSections().get(0);
section.setStartLocation(section.getStartX() + xOffset, section.getStartY() + yOffset);
section.setEndLocation(section.getEndX() + xOffset, section.getEndY() + yOffset);
for (final ElkBendPoint bend : section.getBendPoints()) {
bend.set(bend.getX() + xOffset, bend.getY() + yOffset);
}
// Offset junction points by the node position
selfLoop.getProperty(CoreOptions.JUNCTION_POINTS).offset(xOffset, yOffset);
}
}
use of org.eclipse.elk.graph.ElkConnectableShape in project elk by eclipse.
the class InteractiveLayeredGraphVisitor method shiftOtherNodes.
/**
* Shifts nodes to the right such that edges in the same layer do not exist.
*
* @param movedNode
* The node which connected nodes must be shifted .
* @param layer
* The layer {@code moveNode} is in.
* @param layerNodes
* All existing layers with the containing nodes.
* @param incoming
* Determines if incoming or outgoing edges should be considered. True: incoming edges.
*/
private void shiftOtherNodes(final ElkNode movedNode, final int layer, final List<List<ElkNode>> layerNodes, final boolean incoming) {
List<ElkNode> nodesOfLayer = layerNodes.get(layer);
// get edges
List<ElkEdge> edges = new ArrayList<>();
if (incoming) {
ElkNode root = movedNode.getParent();
for (ElkEdge edge : root.getContainedEdges()) {
for (ElkConnectableShape target : edge.getTargets()) {
if (target.equals(movedNode) || (target instanceof ElkPort && target.eContainer().equals(movedNode))) {
edges.add(edge);
}
}
}
} else {
ElkNode root = movedNode.getParent();
for (ElkEdge edge : root.getContainedEdges()) {
for (ElkConnectableShape target : edge.getSources()) {
if (target.equals(movedNode) || (target instanceof ElkPort && target.eContainer().equals(movedNode))) {
edges.add(edge);
}
}
}
}
for (ElkEdge edge : edges) {
// get connected node
ElkNode node = null;
if (incoming) {
if (edge.getSources().get(0) instanceof ElkPort) {
node = (ElkNode) edge.getSources().get(0).eContainer();
} else if (edge.getSources().get(0) instanceof ElkNode) {
node = (ElkNode) edge.getSources().get(0);
}
} else {
if (edge.getTargets().get(0) instanceof ElkPort) {
node = (ElkNode) edge.getTargets().get(0).eContainer();
} else if (edge.getTargets().get(0) instanceof ElkNode) {
node = (ElkNode) edge.getTargets().get(0);
}
}
// shift node to the next layer
if (nodesOfLayer.contains(node)) {
nodesOfLayer.remove(node);
List<ElkNode> newLayer;
if (layer + 1 < layerNodes.size()) {
newLayer = layerNodes.get(layer + 1);
newLayer.add(node);
// the connected nodes in the layer the node is shifted to must be shifted too
shiftOtherNodes(node, layer + 1, layerNodes, false);
shiftOtherNodes(node, layer + 1, layerNodes, true);
} else {
layerNodes.add(new ArrayList<>(Arrays.asList(node)));
}
}
}
}
use of org.eclipse.elk.graph.ElkConnectableShape in project elk by eclipse.
the class ElkGraphImporter method transformEdge.
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Edge Transformation
/**
* Transforms the given edge if it's not a hyperedge. If it is a hyperedge, throws an exception.
*
* @param elkedge the edge to transform
* @param elkparent the node in the original graph which currently gets transformed into {@code lgraph}
* @param lgraph the layered graph
* @return the transformed edge, or {@code null} if it cannot be transformed
* @throws UnsupportedGraphException if the edge is a hyperedge.
*/
private LEdge transformEdge(final ElkEdge elkedge, final ElkNode elkparent, final LGraph lgraph) {
checkEdgeValidity(elkedge);
// Get a few basic information about the edge
ElkConnectableShape elkSourceShape = elkedge.getSources().get(0);
ElkConnectableShape elkTargetShape = elkedge.getTargets().get(0);
ElkNode elkSourceNode = ElkGraphUtil.connectableShapeToNode(elkSourceShape);
ElkNode elkTargetNode = ElkGraphUtil.connectableShapeToNode(elkTargetShape);
ElkEdgeSection edgeSection = elkedge.getSections().isEmpty() ? null : elkedge.getSections().get(0);
// Find the transformed source and target nodes
LNode sourceLNode = (LNode) nodeAndPortMap.get(elkSourceNode);
LNode targetLNode = (LNode) nodeAndPortMap.get(elkTargetNode);
LPort sourceLPort = null;
LPort targetLPort = null;
// Find the transformed source port, if any
if (elkSourceShape instanceof ElkPort) {
// If the ElkPort is a regular port, it will map to an LPort; if it's an external port, it
// will map to an LNode
LGraphElement sourceElem = nodeAndPortMap.get(elkSourceShape);
if (sourceElem instanceof LPort) {
sourceLPort = (LPort) sourceElem;
} else if (sourceElem instanceof LNode) {
sourceLNode = (LNode) sourceElem;
sourceLPort = sourceLNode.getPorts().get(0);
}
}
// Find the transformed target port, if any
if (elkTargetShape instanceof ElkPort) {
// If the ElkPort is a regular port, it will map to an LPort; if it's an external port, it
// will map to an LNode
LGraphElement targetElem = nodeAndPortMap.get(elkTargetShape);
if (targetElem instanceof LPort) {
targetLPort = (LPort) targetElem;
} else if (targetElem instanceof LNode) {
targetLNode = (LNode) targetElem;
targetLPort = targetLNode.getPorts().get(0);
}
}
// reason, we back out
if (sourceLNode == null || targetLNode == null) {
throw new UnsupportedGraphException("The source or the target of edge " + elkedge + " could not be found. " + "This usually happens when an edge connects a node laid out by ELK Layered to a node in " + "another level of hierarchy laid out by either another instance of ELK Layered or another " + "layout algorithm alltogether. The former can be solved by setting the hierarchyHandling " + "option to INCLUDE_CHILDREN.");
}
// Create a layered edge
LEdge ledge = new LEdge();
ledge.copyProperties(elkedge);
ledge.setProperty(InternalProperties.ORIGIN, elkedge);
// Clear junction points, since they are recomputed from scratch
ledge.setProperty(LayeredOptions.JUNCTION_POINTS, null);
// If we have a self-loop, set the appropriate graph property
Set<GraphProperties> graphProperties = lgraph.getProperty(InternalProperties.GRAPH_PROPERTIES);
if (sourceLNode == targetLNode) {
graphProperties.add(GraphProperties.SELF_LOOPS);
}
// Create source and target ports if they do not exist yet
if (sourceLPort == null) {
PortType portType = PortType.OUTPUT;
KVector sourcePoint = null;
if (edgeSection != null && sourceLNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
sourcePoint = new KVector(edgeSection.getStartX(), edgeSection.getStartY());
// The coordinates need to be relative to us
ElkUtil.toAbsolute(sourcePoint, elkedge.getContainingNode());
ElkUtil.toRelative(sourcePoint, elkparent);
// source), we may need to adjust the coordinates
if (ElkGraphUtil.isDescendant(elkTargetNode, elkSourceNode)) {
// External source port: put it on the west side
portType = PortType.INPUT;
sourcePoint.add(sourceLNode.getPosition());
}
}
sourceLPort = LGraphUtil.createPort(sourceLNode, sourcePoint, portType, lgraph);
}
if (targetLPort == null) {
PortType portType = PortType.INPUT;
KVector targetPoint = null;
if (edgeSection != null && targetLNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
targetPoint = new KVector(edgeSection.getEndX(), edgeSection.getEndY());
// Adjust the coordinates
// MIGRATE Not sure yet if this really does what we want it to do
ElkUtil.toAbsolute(targetPoint, elkedge.getContainingNode());
ElkUtil.toRelative(targetPoint, elkparent);
}
targetLPort = LGraphUtil.createPort(targetLNode, targetPoint, portType, targetLNode.getGraph());
}
// Finally set the source and target of the edge
ledge.setSource(sourceLPort);
ledge.setTarget(targetLPort);
// If the ports have multiple incoming or outgoing edges, the HYPEREDGE property needs to be set
if (sourceLPort.getIncomingEdges().size() > 1 || sourceLPort.getOutgoingEdges().size() > 1 || targetLPort.getIncomingEdges().size() > 1 || targetLPort.getOutgoingEdges().size() > 1) {
graphProperties.add(GraphProperties.HYPEREDGES);
}
// Transform the edge's labels
for (ElkLabel elklabel : elkedge.getLabels()) {
if (!elklabel.getProperty(LayeredOptions.NO_LAYOUT) && !Strings.isNullOrEmpty(elklabel.getText())) {
LLabel llabel = transformLabel(elklabel);
ledge.getLabels().add(llabel);
// edge label placement is actually properly defined
switch(llabel.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT)) {
case HEAD:
case TAIL:
graphProperties.add(GraphProperties.END_LABELS);
break;
case CENTER:
graphProperties.add(GraphProperties.CENTER_LABELS);
llabel.setProperty(LayeredOptions.EDGE_LABELS_PLACEMENT, EdgeLabelPlacement.CENTER);
}
}
}
// Copy the original bend points of the edge in case they are required
CrossingMinimizationStrategy crossMinStrat = lgraph.getProperty(LayeredOptions.CROSSING_MINIMIZATION_STRATEGY);
NodePlacementStrategy nodePlaceStrat = lgraph.getProperty(LayeredOptions.NODE_PLACEMENT_STRATEGY);
boolean bendPointsRequired = crossMinStrat == CrossingMinimizationStrategy.INTERACTIVE || nodePlaceStrat == NodePlacementStrategy.INTERACTIVE;
if (edgeSection != null && !edgeSection.getBendPoints().isEmpty() && bendPointsRequired) {
KVectorChain originalBendpoints = ElkUtil.createVectorChain(edgeSection);
KVectorChain importedBendpoints = new KVectorChain();
// MIGRATE We may have to do some coordinate conversion here
for (KVector point : originalBendpoints) {
importedBendpoints.add(new KVector(point));
}
ledge.setProperty(InternalProperties.ORIGINAL_BENDPOINTS, importedBendpoints);
}
return ledge;
}
Aggregations