Search in sources :

Example 1 with ElkConnectableShape

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);
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) Diagram(org.eclipse.sirius.components.diagrams.Diagram) LinkedHashMap(java.util.LinkedHashMap)

Example 2 with ElkConnectableShape

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);
    }
}
Also used : ConnectionEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) ElkNode(org.eclipse.elk.graph.ElkNode) HashMap(java.util.HashMap) ElkPort(org.eclipse.elk.graph.ElkPort) ResizableCompartmentEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ResizableCompartmentEditPart) ShapeNodeEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart) RootEditPart(org.eclipse.gef.RootEditPart) CompartmentEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart) RenderedDiagramRootEditPart(org.eclipse.gmf.runtime.diagram.ui.render.editparts.RenderedDiagramRootEditPart) EditPart(org.eclipse.gef.EditPart) IGraphicalEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart) AbstractBorderItemEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderItemEditPart) LabelEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.LabelEditPart) ConnectionEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart) DiagramEditPart(org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) EObject(org.eclipse.emf.ecore.EObject) EObject(org.eclipse.emf.ecore.EObject) EdgeLabelPlacement(org.eclipse.elk.core.options.EdgeLabelPlacement) KVector(org.eclipse.elk.core.math.KVector) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) EReference(org.eclipse.emf.ecore.EReference) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 3 with ElkConnectableShape

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);
    }
}
Also used : ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 4 with ElkConnectableShape

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)));
            }
        }
    }
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) ArrayList(java.util.ArrayList) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 5 with ElkConnectableShape

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;
}
Also used : UnsupportedGraphException(org.eclipse.elk.core.UnsupportedGraphException) NodePlacementStrategy(org.eclipse.elk.alg.layered.options.NodePlacementStrategy) ElkNode(org.eclipse.elk.graph.ElkNode) LLabel(org.eclipse.elk.alg.layered.graph.LLabel) GraphProperties(org.eclipse.elk.alg.layered.options.GraphProperties) ElkPort(org.eclipse.elk.graph.ElkPort) LGraphElement(org.eclipse.elk.alg.layered.graph.LGraphElement) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) ElkLabel(org.eclipse.elk.graph.ElkLabel) LPort(org.eclipse.elk.alg.layered.graph.LPort) CrossingMinimizationStrategy(org.eclipse.elk.alg.layered.options.CrossingMinimizationStrategy) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) PortType(org.eclipse.elk.alg.layered.options.PortType)

Aggregations

ElkConnectableShape (org.eclipse.elk.graph.ElkConnectableShape)21 ElkNode (org.eclipse.elk.graph.ElkNode)12 ElkPort (org.eclipse.elk.graph.ElkPort)11 ElkEdge (org.eclipse.elk.graph.ElkEdge)10 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)6 KVector (org.eclipse.elk.core.math.KVector)4 ElkGraphElement (org.eclipse.elk.graph.ElkGraphElement)4 ElkLabel (org.eclipse.elk.graph.ElkLabel)3 HashMap (java.util.HashMap)2 ElkBendPoint (org.eclipse.elk.graph.ElkBendPoint)2 ElkNodeImpl (org.eclipse.elk.graph.impl.ElkNodeImpl)2 ElkPortImpl (org.eclipse.elk.graph.impl.ElkPortImpl)2 ENotificationImpl (org.eclipse.emf.ecore.impl.ENotificationImpl)2 ArrayList (java.util.ArrayList)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedList (java.util.LinkedList)1 ListIterator (java.util.ListIterator)1 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)1 LGraphElement (org.eclipse.elk.alg.layered.graph.LGraphElement)1 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)1