Search in sources :

Example 1 with KVectorChain

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

the class HierarchicalPortOrthogonalEdgeRouter method correctSlantedEdgeSegments.

/**
 * Goes over the eastern and western hierarchical dummy nodes in the given layer and checks
 * whether their incident edges have slanted segments. Note that only the first and last
 * segment needs to be checked.
 *
 * @param layer the layer.
 */
private void correctSlantedEdgeSegments(final Layer layer) {
    for (LNode node : layer) {
        if (node.getType() != NodeType.EXTERNAL_PORT) {
            // We're only looking for hierarchical port dummies
            continue;
        }
        PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
        if (extPortSide == PortSide.EAST || extPortSide == PortSide.WEST) {
            for (LEdge edge : node.getConnectedEdges()) {
                KVectorChain bendPoints = edge.getBendPoints();
                if (bendPoints.isEmpty()) {
                    // TODO: The edge has no bend points yet, but may still be slanted. Handle that!
                    continue;
                }
                // Correct a slanted segment connected to the source port if it belongs to our node
                LPort sourcePort = edge.getSource();
                if (sourcePort.getNode() == node) {
                    KVector firstBendPoint = bendPoints.getFirst();
                    firstBendPoint.y = sourcePort.getAbsoluteAnchor().y;
                }
                // Correct a slanted segment connected to the target port if it belongs to our node
                LPort targetPort = edge.getTarget();
                if (targetPort.getNode() == node) {
                    KVector lastBendPoint = bendPoints.getLast();
                    lastBendPoint.y = targetPort.getAbsoluteAnchor().y;
                }
            }
        }
    }
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) PortSide(org.eclipse.elk.core.options.PortSide) KVector(org.eclipse.elk.core.math.KVector)

Example 2 with KVectorChain

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

the class HierarchicalPortOrthogonalEdgeRouter method removeTemporaryNorthSouthDummies.

// /////////////////////////////////////////////////////////////////////////////
// STEP 4: REMOVE TEMPORARY DUMMIES
/**
 * Removes the temporary hierarchical port dummies, reconnecting their incoming and outgoing
 * edges to the original dummies and setting the appropriate bend points.
 *
 * @param layeredGraph the layered graph.
 */
private void removeTemporaryNorthSouthDummies(final LGraph layeredGraph) {
    List<LNode> nodesToRemove = Lists.newArrayList();
    // Iterate through all layers
    for (Layer layer : layeredGraph) {
        for (LNode node : layer) {
            if (node.getType() != NodeType.EXTERNAL_PORT) {
                // We're only looking for hierarchical port dummies
                continue;
            }
            if (!node.hasProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY)) {
                // We're only looking for temporary north / south dummies
                continue;
            }
            // There must be a port where all edges come in, another port where edges go out, and
            // a port with an edge connecting node and origin (that one was added previously by
            // this processor)
            LPort nodeInPort = null;
            LPort nodeOutPort = null;
            LPort nodeOriginPort = null;
            for (LPort port : node.getPorts()) {
                switch(port.getSide()) {
                    case WEST:
                        nodeInPort = port;
                        break;
                    case EAST:
                        nodeOutPort = port;
                        break;
                    default:
                        nodeOriginPort = port;
                }
            }
            // Find the edge connecting this dummy to the original external port dummy that we
            // restored just a while ago
            LEdge nodeToOriginEdge = nodeOriginPort.getOutgoingEdges().get(0);
            // Compute bend points for incoming edges
            KVectorChain incomingEdgeBendPoints = new KVectorChain(nodeToOriginEdge.getBendPoints());
            KVector firstBendPoint = new KVector(nodeOriginPort.getPosition());
            firstBendPoint.add(node.getPosition());
            incomingEdgeBendPoints.add(0, firstBendPoint);
            // Compute bend points for outgoing edges
            KVectorChain outgoingEdgeBendPoints = KVectorChain.reverse(nodeToOriginEdge.getBendPoints());
            KVector lastBendPoint = new KVector(nodeOriginPort.getPosition());
            lastBendPoint.add(node.getPosition());
            outgoingEdgeBendPoints.add(lastBendPoint);
            // Retrieve the original hierarchical port dummy
            LNode replacedDummy = (LNode) node.getProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY);
            LPort replacedDummyPort = replacedDummy.getPorts().get(0);
            // Reroute all the input port's edges
            LEdge[] edges = nodeInPort.getIncomingEdges().toArray(new LEdge[0]);
            for (LEdge edge : edges) {
                edge.setTarget(replacedDummyPort);
                edge.getBendPoints().addAllAsCopies(edge.getBendPoints().size(), incomingEdgeBendPoints);
            }
            // Reroute all the output port's edges
            edges = LGraphUtil.toEdgeArray(nodeOutPort.getOutgoingEdges());
            for (LEdge edge : edges) {
                edge.setSource(replacedDummyPort);
                edge.getBendPoints().addAllAsCopies(0, outgoingEdgeBendPoints);
            }
            // Remove connection between node and original hierarchical port dummy
            nodeToOriginEdge.setSource(null);
            nodeToOriginEdge.setTarget(null);
            // Remember the temporary node for removal
            nodesToRemove.add(node);
        }
    }
    // Remove nodes
    for (LNode node : nodesToRemove) {
        node.setLayer(null);
    }
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector) Layer(org.eclipse.elk.alg.layered.graph.Layer)

Example 3 with KVectorChain

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

the class GraphTransformer method mirrorX.

// /////////////////////////////////////////////////////////////////////////////
// Mirror Horizontally
/**
 * Mirror the x coordinates of the given graph.
 *
 * @param nodes the nodes of the graph to transpose
 * @param graph the graph the nodes are part of
 */
private void mirrorX(final List<LNode> nodes, final LGraph graph) {
    /* Assuming that no nodes extend into negative x coordinates, mirroring a node means that the
         * space left to its left border equals the space right to its right border when mirrored. In
         * mathematical terms:
         *     oldPosition.x = graphWidth - newPosition.x - nodeWidth
         * We use the offset variable to store graphWidth, since that's the constant offset against which
         * we calculate the new node positions.
         * This, however, stops to work once nodes are allowed to extend into negative coordinates. Then,
         * we have to subtract from the graphWidth the amount of space the graph extends into negative
         * coordinates. This amount is saved in the graph's graphOffset. Thus, our offset here becomes:
         *     offset = graphWidth - graphOffset.x 
         */
    double offset = 0;
    // over its nodes
    if (graph.getSize().x == 0) {
        for (LNode node : nodes) {
            offset = Math.max(offset, node.getPosition().x + node.getSize().x + node.getMargin().right);
        }
    } else {
        offset = graph.getSize().x - graph.getOffset().x;
    }
    offset -= graph.getOffset().x;
    // mirror all nodes, ports, edges, and labels
    for (LNode node : nodes) {
        mirrorX(node.getPosition(), offset - node.getSize().x);
        mirrorX(node.getPadding());
        mirrorNodeLabelPlacementX(node);
        // mirror position
        if (node.getAllProperties().containsKey(LayeredOptions.POSITION)) {
            mirrorX(node.getProperty(LayeredOptions.POSITION), offset - node.getSize().x);
        }
        // mirror the alignment
        switch(node.getProperty(LayeredOptions.ALIGNMENT)) {
            case LEFT:
                node.setProperty(LayeredOptions.ALIGNMENT, Alignment.RIGHT);
                break;
            case RIGHT:
                node.setProperty(LayeredOptions.ALIGNMENT, Alignment.LEFT);
                break;
        }
        KVector nodeSize = node.getSize();
        for (LPort port : node.getPorts()) {
            mirrorX(port.getPosition(), nodeSize.x - port.getSize().x);
            mirrorX(port.getAnchor(), port.getSize().x);
            mirrorPortSideX(port);
            reverseIndex(port);
            for (LEdge edge : port.getOutgoingEdges()) {
                // Mirror bend points
                for (KVector bendPoint : edge.getBendPoints()) {
                    mirrorX(bendPoint, offset);
                }
                // Mirror junction points
                KVectorChain junctionPoints = edge.getProperty(LayeredOptions.JUNCTION_POINTS);
                if (junctionPoints != null) {
                    for (KVector jp : junctionPoints) {
                        mirrorX(jp, offset);
                    }
                }
                // Mirror edge label positions
                for (LLabel label : edge.getLabels()) {
                    mirrorX(label.getPosition(), offset - label.getSize().x);
                }
            }
            // Mirror port label positions
            for (LLabel label : port.getLabels()) {
                mirrorX(label.getPosition(), port.getSize().x - label.getSize().x);
            }
        }
        // External port dummy?
        if (node.getType() == NodeType.EXTERNAL_PORT) {
            mirrorExternalPortSideX(node);
            mirrorLayerConstraintX(node);
        }
        // Mirror node labels
        for (LLabel label : node.getLabels()) {
            mirrorNodeLabelPlacementX(label);
            mirrorX(label.getPosition(), nodeSize.x - label.getSize().x);
        }
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector)

Example 4 with KVectorChain

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

the class GraphTransformer method mirrorY.

// /////////////////////////////////////////////////////////////////////////////
// Mirror Vertically
/**
 * Mirror the y coordinates of the given graph.
 *
 * @param nodes the nodes of the graph to transpose
 * @param graph the graph the nodes are part of
 */
private void mirrorY(final List<LNode> nodes, final LGraph graph) {
    // See mirrorX for an explanation of how the offset is calculated
    double offset = 0;
    if (graph.getSize().y == 0) {
        for (LNode node : nodes) {
            offset = Math.max(offset, node.getPosition().y + node.getSize().y + node.getMargin().bottom);
        }
    } else {
        offset = graph.getSize().y - graph.getOffset().y;
    }
    offset -= graph.getOffset().y;
    // mirror all nodes, ports, edges, and labels
    for (LNode node : nodes) {
        mirrorY(node.getPosition(), offset - node.getSize().y);
        mirrorY(node.getPadding());
        mirrorNodeLabelPlacementY(node);
        // mirror position
        if (node.getAllProperties().containsKey(LayeredOptions.POSITION)) {
            mirrorY(node.getProperty(LayeredOptions.POSITION), offset - node.getSize().y);
        }
        // mirror the alignment
        switch(node.getProperty(LayeredOptions.ALIGNMENT)) {
            case TOP:
                node.setProperty(LayeredOptions.ALIGNMENT, Alignment.BOTTOM);
                break;
            case BOTTOM:
                node.setProperty(LayeredOptions.ALIGNMENT, Alignment.TOP);
                break;
        }
        KVector nodeSize = node.getSize();
        for (LPort port : node.getPorts()) {
            mirrorY(port.getPosition(), nodeSize.y - port.getSize().y);
            mirrorY(port.getAnchor(), port.getSize().y);
            mirrorPortSideY(port);
            reverseIndex(port);
            for (LEdge edge : port.getOutgoingEdges()) {
                // Mirror bend points
                for (KVector bendPoint : edge.getBendPoints()) {
                    mirrorY(bendPoint, offset);
                }
                // Mirror junction points
                KVectorChain junctionPoints = edge.getProperty(LayeredOptions.JUNCTION_POINTS);
                if (junctionPoints != null) {
                    for (KVector jp : junctionPoints) {
                        mirrorY(jp, offset);
                    }
                }
                // Mirror edge label positions
                for (LLabel label : edge.getLabels()) {
                    mirrorY(label.getPosition(), offset - label.getSize().y);
                }
            }
            // Mirror port label positions
            for (LLabel label : port.getLabels()) {
                mirrorY(label.getPosition(), port.getSize().y - label.getSize().y);
            }
        }
        // External port dummy?
        if (node.getType() == NodeType.EXTERNAL_PORT) {
            mirrorExternalPortSideY(node);
            mirrorInLayerConstraintY(node);
        }
        // Mirror node labels
        for (LLabel label : node.getLabels()) {
            mirrorNodeLabelPlacementY(label);
            mirrorY(label.getPosition(), nodeSize.y - label.getSize().y);
        }
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) KVectorChain(org.eclipse.elk.core.math.KVectorChain) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) KVector(org.eclipse.elk.core.math.KVector)

Example 5 with KVectorChain

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

the class GraphRenderer method renderEdge.

/**
 * Paints an edge for the given dirty area.
 *
 * @param edge the edge to paint
 * @param graphics the graphics context used to paint
 * @param area dirty area that needs painting
 * @param offset offset to be added to relative coordinates
 * @param labelAlpha alpha value for labels
 */
private void renderEdge(final ElkEdge edge, final GC graphics, final Rectangle area, final KVector offset, final int labelAlpha) {
    if (configurator.getEdgeColor() == null) {
        return;
    }
    // Find our if the edge is actually eligible to be painted
    if (isEdgeFullyContainedInGraphToDraw(edge)) {
        // Get a PaintRectangle ready for the edge
        PaintRectangle rect = boundsMap.get(edge);
        if (rect == null) {
            rect = new PaintRectangle(edge, offset, scale);
            boundsMap.put(edge, rect);
        }
        if (!rect.painted && rect.intersects(area)) {
            // Gather some information
            final boolean splineEdge = edge.getProperty(CoreOptions.EDGE_ROUTING) == EdgeRouting.SPLINES;
            final boolean directedEdge = edge.getProperty(CoreOptions.EDGE_TYPE) != EdgeType.UNDIRECTED;
            graphics.setAlpha(255);
            // The background color is required to fill the arrow of directed edges
            graphics.setForeground(configurator.getEdgeColor());
            graphics.setBackground(configurator.getEdgeColor());
            for (ElkEdgeSection edgeSection : edge.getSections()) {
                KVectorChain bendPoints = ElkUtil.createVectorChain(edgeSection);
                bendPoints.scale(scale).offset(offset);
                // Draw the damn edge already...!
                Path path = new Path(graphics.getDevice());
                Iterator<KVector> pointIter = bendPoints.iterator();
                KVector startPoint = pointIter.next();
                path.moveTo((float) startPoint.x, (float) startPoint.y);
                KVector point1 = null;
                KVector point2 = null;
                while (pointIter.hasNext()) {
                    if (splineEdge) {
                        if (point1 == null) {
                            point1 = pointIter.next();
                        } else if (point2 == null) {
                            point2 = pointIter.next();
                        } else {
                            KVector endPoint = pointIter.next();
                            path.cubicTo((float) point1.x, (float) point1.y, (float) point2.x, (float) point2.y, (float) endPoint.x, (float) endPoint.y);
                            point1 = null;
                            point2 = null;
                        }
                    } else {
                        KVector nextPoint = pointIter.next();
                        path.lineTo((float) nextPoint.x, (float) nextPoint.y);
                    }
                }
                if (splineEdge && point2 != null) {
                    path.quadTo((float) point1.x, (float) point1.y, (float) point2.x, (float) point2.y);
                } else if (splineEdge && point1 != null) {
                    path.lineTo((float) point1.x, (float) point1.y);
                }
                graphics.drawPath(path);
                if (directedEdge) {
                    // Draw an arrow at the last segment of the connection
                    KVector referencePoint;
                    if (splineEdge && (bendPoints.size() - 1) % 3 != 1) {
                        int beginIndex;
                        if ((bendPoints.size() - 1) % 3 == 2) {
                            beginIndex = bendPoints.size() - 2;
                        } else {
                            beginIndex = bendPoints.size() - 3;
                        }
                        referencePoint = ElkMath.getPointOnBezierSegment(0.5, bendPoints.toArray(beginIndex));
                    } else {
                        referencePoint = bendPoints.get(bendPoints.size() - 2);
                    }
                    int[] arrowPoly = makeArrow(referencePoint, bendPoints.getLast());
                    if (arrowPoly != null) {
                        graphics.fillPolygon(arrowPoly);
                    }
                }
            }
            rect.painted = true;
        }
    }
    // paint junction points
    KVectorChain vc = edge.getProperty(CoreOptions.JUNCTION_POINTS);
    if (vc != null) {
        for (KVector v : vc) {
            KVector center = v.clone().scale(scale).add(offset).sub(2, 2);
            graphics.fillOval((int) center.x, (int) center.y, 6, 6);
        }
    }
    // paint the edge labels
    if (configurator.getEdgeLabelFont() != null) {
        graphics.setFont(configurator.getEdgeLabelFont());
        for (ElkLabel label : edge.getLabels()) {
            renderLabel(label, graphics, area, offset, labelAlpha);
        }
    }
}
Also used : Path(org.eclipse.swt.graphics.Path) ElkLabel(org.eclipse.elk.graph.ElkLabel) KVectorChain(org.eclipse.elk.core.math.KVectorChain) KVector(org.eclipse.elk.core.math.KVector) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint)

Aggregations

KVectorChain (org.eclipse.elk.core.math.KVectorChain)65 KVector (org.eclipse.elk.core.math.KVector)49 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)18 LPort (org.eclipse.elk.alg.layered.graph.LPort)16 LNode (org.eclipse.elk.alg.layered.graph.LNode)13 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)13 ElkLabel (org.eclipse.elk.graph.ElkLabel)10 Test (org.junit.Test)10 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)8 ElkNode (org.eclipse.elk.graph.ElkNode)7 ArrayList (java.util.ArrayList)5 ElkEdge (org.eclipse.elk.graph.ElkEdge)5 ElkBendPoint (org.eclipse.elk.graph.ElkBendPoint)4 DCElement (org.eclipse.elk.alg.disco.graph.DCElement)3 ElkPadding (org.eclipse.elk.core.math.ElkPadding)3 ElkPort (org.eclipse.elk.graph.ElkPort)3 Line2D (java.awt.geom.Line2D)2 LinkedList (java.util.LinkedList)2 PointList (org.eclipse.draw2d.geometry.PointList)2 DCDirection (org.eclipse.elk.alg.disco.graph.DCDirection)2