Search in sources :

Example 31 with KVector

use of org.eclipse.elk.core.math.KVector 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 32 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class StraightLineEdgeRouter method routeEdges.

/**
 * Route edges from node center to node center. Then clip it, to not cross the node.
 */
public void routeEdges(final ElkNode node) {
    for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) {
        if (!(edge.getSources().get(0) instanceof ElkPort)) {
            ElkNode target = ElkGraphUtil.connectableShapeToNode(edge.getTargets().get(0));
            if (!edge.isHierarchical()) {
                double sourceX = node.getX() + node.getWidth() / 2;
                double sourceY = node.getY() + node.getHeight() / 2;
                double targetX = target.getX() + target.getWidth() / 2;
                double targetY = target.getY() + target.getHeight() / 2;
                // Clipping
                KVector vector = new KVector();
                vector.x = targetX - sourceX;
                vector.y = targetY - sourceY;
                KVector sourceClip = new KVector(vector.x, vector.y);
                ElkMath.clipVector(sourceClip, node.getWidth(), node.getHeight());
                vector.x -= sourceClip.x;
                vector.y -= sourceClip.y;
                sourceX = targetX - vector.x;
                sourceY = targetY - vector.y;
                KVector targetClip = new KVector(vector.x, vector.y);
                ElkMath.clipVector(targetClip, target.getWidth(), target.getHeight());
                vector.x -= targetClip.x;
                vector.y -= targetClip.y;
                targetX = sourceX + vector.x;
                targetY = sourceY + vector.y;
                ElkEdgeSection section = ElkGraphUtil.firstEdgeSection(edge, true, true);
                section.setStartLocation(sourceX, sourceY);
                section.setEndLocation(targetX, targetY);
                routeEdges(target);
            }
        }
    }
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) KVector(org.eclipse.elk.core.math.KVector) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 33 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class RectPackingLayoutProvider method layout.

/**
 * Calculating and applying layout to the model.
 */
@Override
public void layout(final ElkNode layoutGraph, final IElkProgressMonitor progressMonitor) {
    progressMonitor.begin("Rectangle Packing", 1);
    if (progressMonitor.isLoggingEnabled()) {
        progressMonitor.logGraph(layoutGraph, "Input");
    }
    // The desired aspect ratio.
    double aspectRatio = layoutGraph.getProperty(RectPackingOptions.ASPECT_RATIO);
    // The strategy for the initial width approximation.
    OptimizationGoal goal = layoutGraph.getProperty(RectPackingOptions.OPTIMIZATION_GOAL);
    // Option for better width approximation.
    boolean lastPlaceShift = layoutGraph.getProperty(RectPackingOptions.LAST_PLACE_SHIFT);
    // Option to only do the initial width approximation.
    boolean onlyFirstIteration = layoutGraph.getProperty(RectPackingOptions.ONLY_FIRST_ITERATION);
    // Option whether the nodes should be expanded to fill the bounding rectangle.
    boolean expandNodes = layoutGraph.getProperty(RectPackingOptions.EXPAND_NODES);
    // The padding surrounding the drawing.
    ElkPadding padding = layoutGraph.getProperty(RectPackingOptions.PADDING);
    // The spacing between two nodes.
    double nodeNodeSpacing = layoutGraph.getProperty(RectPackingOptions.SPACING_NODE_NODE);
    // Whether the nodes are compacted after the initial placement.
    boolean compaction = layoutGraph.getProperty(RectPackingOptions.ROW_COMPACTION);
    // Whether the nodes should be expanded to fit the aspect ratio during node expansion.
    // Only effective if nodes are expanded.
    boolean expandToAspectRatio = layoutGraph.getProperty(RectPackingOptions.EXPAND_TO_ASPECT_RATIO);
    // Whether interactive layout is activ.
    boolean interactive = layoutGraph.getProperty(RectPackingOptions.INTERACTIVE);
    // A target width for the algorithm. If this is set the width approximation step is skipped.
    double targetWidth = layoutGraph.getProperty(RectPackingOptions.TARGET_WIDTH);
    List<ElkNode> rectangles = layoutGraph.getChildren();
    DrawingUtil.resetCoordinates(rectangles);
    DrawingData drawing;
    if (interactive) {
        List<ElkNode> fixedNodes = new ArrayList<>();
        for (ElkNode elkNode : rectangles) {
            if (elkNode.hasProperty(RectPackingOptions.DESIRED_POSITION)) {
                fixedNodes.add(elkNode);
            }
        }
        for (ElkNode elkNode : fixedNodes) {
            rectangles.remove(elkNode);
        }
        Collections.sort(fixedNodes, (a, b) -> {
            int positionA = a.getProperty(RectPackingOptions.DESIRED_POSITION);
            int positionB = b.getProperty(RectPackingOptions.DESIRED_POSITION);
            if (positionA == positionB) {
                return -1;
            } else {
                return Integer.compare(positionA, positionB);
            }
        });
        for (ElkNode elkNode : fixedNodes) {
            int position = elkNode.getProperty(RectPackingOptions.DESIRED_POSITION);
            position = Math.min(position, rectangles.size());
            rectangles.add(position, elkNode);
        }
        int index = 0;
        for (ElkNode elkNode : rectangles) {
            elkNode.setProperty(RectPackingOptions.CURRENT_POSITION, index);
            index++;
        }
    }
    // Get minimum size of parent.
    KVector minSize = ElkUtil.effectiveMinSizeConstraintFor(layoutGraph);
    // Remove padding to get the space the algorithm can use.
    minSize.x -= padding.getHorizontal();
    minSize.y -= padding.getVertical();
    double maxWidth = minSize.x;
    if (targetWidth < 0 || targetWidth < minSize.x) {
        // Initial width approximation.
        AreaApproximation firstIt = new AreaApproximation(aspectRatio, goal, lastPlaceShift);
        drawing = firstIt.approxBoundingBox(rectangles, nodeNodeSpacing, padding);
        if (progressMonitor.isLoggingEnabled()) {
            progressMonitor.logGraph(layoutGraph, "After approximation");
        }
    } else {
        drawing = new DrawingData(aspectRatio, targetWidth, 0, DrawingDataDescriptor.WHOLE_DRAWING);
    }
    // Readd padding for next steps.
    minSize.x += padding.getHorizontal();
    minSize.y += padding.getVertical();
    // Placement according to approximated width.
    if (!onlyFirstIteration) {
        DrawingUtil.resetCoordinates(rectangles);
        RowFillingAndCompaction secondIt = new RowFillingAndCompaction(aspectRatio, expandNodes, expandToAspectRatio, compaction, nodeNodeSpacing);
        // Modify the initial approximation if necessary.
        maxWidth = Math.max(minSize.x, drawing.getDrawingWidth());
        // Run placement, compaction, and expansion (if enabled).
        drawing = secondIt.start(rectangles, maxWidth, minSize, progressMonitor, layoutGraph);
    }
    // Final touch.
    applyPadding(rectangles, padding);
    ElkUtil.resizeNode(layoutGraph, drawing.getDrawingWidth() + padding.getHorizontal(), drawing.getDrawingHeight() + padding.getVertical(), false, true);
    // if requested, compute nodes's dimensions, place node labels, ports, port labels, etc.
    if (!layoutGraph.getProperty(RectPackingOptions.OMIT_NODE_MICRO_LAYOUT)) {
        NodeMicroLayout.forGraph(layoutGraph).execute();
    }
    if (progressMonitor.isLoggingEnabled()) {
        progressMonitor.logGraph(layoutGraph, "Output");
    }
    progressMonitor.done();
}
Also used : RowFillingAndCompaction(org.eclipse.elk.alg.rectpacking.seconditeration.RowFillingAndCompaction) ElkNode(org.eclipse.elk.graph.ElkNode) DrawingData(org.eclipse.elk.alg.rectpacking.util.DrawingData) ArrayList(java.util.ArrayList) KVector(org.eclipse.elk.core.math.KVector) ElkPadding(org.eclipse.elk.core.math.ElkPadding) OptimizationGoal(org.eclipse.elk.alg.rectpacking.options.OptimizationGoal) AreaApproximation(org.eclipse.elk.alg.rectpacking.firstiteration.AreaApproximation)

Example 34 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class ElkGraphImporter method updateGraph.

@Override
public void updateGraph(final Graph g) {
    Map<KVector, Pair<Node, ElkNode>> updatedNodeMap = Maps.newHashMap();
    // reset graph
    g.tEdges = null;
    g.tree = null;
    // update nodes
    for (Node n : g.vertices) {
        Pair<Node, ElkNode> original = nodeMap.get(n.originalVertex);
        n.originalVertex = n.rect.getCenter();
        updatedNodeMap.put(n.originalVertex, original);
    }
    nodeMap = updatedNodeMap;
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) Node(org.eclipse.elk.alg.common.spore.Node) ElkNode(org.eclipse.elk.graph.ElkNode) KVector(org.eclipse.elk.core.math.KVector) Pair(org.eclipse.elk.core.util.Pair)

Example 35 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class ElkGraphImporter method importGraph.

@Override
public Graph importGraph(final ElkNode inputGraph) {
    elkGraph = inputGraph;
    nodeMap = Maps.newHashMap();
    // calculate margins
    ElkGraphAdapter adapter = ElkGraphAdapters.adapt(elkGraph);
    NodeDimensionCalculation.calculateNodeMargins(adapter);
    // retrieve layout options
    String preferredRootID = elkGraph.getProperty(SporeCompactionOptions.PROCESSING_ORDER_PREFERRED_ROOT);
    SpanningTreeCostFunction costFunctionID = elkGraph.getProperty(SporeCompactionOptions.PROCESSING_ORDER_SPANNING_TREE_COST_FUNCTION);
    TreeConstructionStrategy treeConstructionStrategy = elkGraph.getProperty(SporeCompactionOptions.PROCESSING_ORDER_TREE_CONSTRUCTION);
    CompactionStrategy compactionStrategy = elkGraph.getProperty(SporeCompactionOptions.COMPACTION_COMPACTION_STRATEGY);
    RootSelection rootSelection = elkGraph.getProperty(SporeCompactionOptions.PROCESSING_ORDER_ROOT_SELECTION);
    spacingNodeNode = elkGraph.getProperty(SporeCompactionOptions.SPACING_NODE_NODE);
    ICostFunction costFunction = centerDistance;
    switch(costFunctionID) {
        case CENTER_DISTANCE:
            costFunction = centerDistance;
            break;
        case CIRCLE_UNDERLAP:
            costFunction = circleUnderlap;
            break;
        case RECTANGLE_UNDERLAP:
            costFunction = rectangleUnderlap;
            break;
        case INVERTED_OVERLAP:
            costFunction = invertedOverlap;
            break;
        case MINIMUM_ROOT_DISTANCE:
            costFunction = minimumRootDistance;
            break;
        default:
            throw new IllegalArgumentException("No implementation available for " + costFunctionID.toString());
    }
    // instantiate Graph
    graph = new Graph(costFunction, treeConstructionStrategy, compactionStrategy);
    graph.setProperty(InternalProperties.DEBUG_SVG, elkGraph.getProperty(SporeCompactionOptions.DEBUG_MODE));
    graph.orthogonalCompaction = elkGraph.getProperty(SporeCompactionOptions.COMPACTION_ORTHOGONAL);
    if (elkGraph.getChildren().isEmpty()) {
        // don't bother
        return graph;
    }
    // create Nodes representing the ElkNodes
    for (ElkNode elkNode : elkGraph.getChildren()) {
        double halfWidth = elkNode.getWidth() / 2;
        double halfHeight = elkNode.getHeight() / 2;
        KVector vertex = new KVector(elkNode.getX() + halfWidth, elkNode.getY() + halfHeight);
        // randomly shift identical points a tiny bit to make them unique
        while (nodeMap.containsKey(vertex)) {
            // SUPPRESS CHECKSTYLE NEXT 1 MagicNumber
            vertex.add((Math.random() - 0.5) * 0.001, (Math.random() - 0.5) * 0.001);
        // If two positions were identical, their corresponding edge in the spanning tree would be
        // of zero length, had no direction, and couldn't be scaled by anything.
        }
        ElkMargin margin = elkNode.getProperty(CoreOptions.MARGINS);
        Node node = new Node(vertex, new ElkRectangle(vertex.x - halfWidth - spacingNodeNode / 2 - margin.left, vertex.y - halfHeight - spacingNodeNode / 2 - margin.top, elkNode.getWidth() + spacingNodeNode + margin.getHorizontal(), elkNode.getHeight() + spacingNodeNode + margin.getVertical()));
        graph.vertices.add(node);
        nodeMap.put(vertex, Pair.of(node, elkNode));
    }
    // spanning tree root selection method
    switch(rootSelection) {
        case FIXED:
            if (preferredRootID == null) {
                // get first Node in list if no ID specified
                graph.preferredRoot = graph.vertices.get(0);
            } else {
                // find Node associated with the ElkNode containing the ID
                for (Node node : graph.vertices) {
                    String id = nodeMap.get(node.originalVertex).getSecond().getIdentifier();
                    if (id != null && id.equals(preferredRootID)) {
                        graph.preferredRoot = node;
                    }
                }
            }
            break;
        case CENTER_NODE:
            // find node that is most central in the drawing
            KVector center = new KVector(elkGraph.getWidth(), elkGraph.getHeight());
            // CHECKSTYLEOFF MagicNumber
            center.scale(0.5);
            center.add(elkGraph.getX(), elkGraph.getY());
            double closest = Double.POSITIVE_INFINITY;
            for (Node node : graph.vertices) {
                double distance = node.originalVertex.distance(center);
                if (distance < closest) {
                    closest = distance;
                    graph.preferredRoot = node;
                }
            }
            break;
        default:
            throw new IllegalArgumentException("No implementation available for " + rootSelection.toString());
    }
    return graph;
}
Also used : ICostFunction(org.eclipse.elk.alg.common.ICostFunction) SpanningTreeCostFunction(org.eclipse.elk.alg.spore.options.SpanningTreeCostFunction) CompactionStrategy(org.eclipse.elk.alg.spore.options.CompactionStrategy) ElkNode(org.eclipse.elk.graph.ElkNode) Node(org.eclipse.elk.alg.common.spore.Node) ElkNode(org.eclipse.elk.graph.ElkNode) ElkMargin(org.eclipse.elk.core.math.ElkMargin) RootSelection(org.eclipse.elk.alg.spore.options.RootSelection) Graph(org.eclipse.elk.alg.spore.graph.Graph) TreeConstructionStrategy(org.eclipse.elk.alg.spore.options.TreeConstructionStrategy) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle) ElkGraphAdapter(org.eclipse.elk.core.util.adapters.ElkGraphAdapters.ElkGraphAdapter)

Aggregations

KVector (org.eclipse.elk.core.math.KVector)292 KVectorChain (org.eclipse.elk.core.math.KVectorChain)52 ElkNode (org.eclipse.elk.graph.ElkNode)49 LNode (org.eclipse.elk.alg.layered.graph.LNode)39 LPort (org.eclipse.elk.alg.layered.graph.LPort)37 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)36 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)35 Test (org.junit.Test)30 ElkEdge (org.eclipse.elk.graph.ElkEdge)28 ElkLabel (org.eclipse.elk.graph.ElkLabel)27 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)26 ElkPadding (org.eclipse.elk.core.math.ElkPadding)25 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)20 PortSide (org.eclipse.elk.core.options.PortSide)19 ElkPort (org.eclipse.elk.graph.ElkPort)18 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)17 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)15 ArrayList (java.util.ArrayList)13 Layer (org.eclipse.elk.alg.layered.graph.Layer)12 LMargin (org.eclipse.elk.alg.layered.graph.LMargin)11