Search in sources :

Example 46 with LEdge

use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.

the class CommentPreprocessor method process.

@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
    monitor.begin("Comment pre-processing", 1);
    int commentBoxCount = 0;
    Iterator<LNode> nodeIter = layeredGraph.getLayerlessNodes().iterator();
    while (nodeIter.hasNext()) {
        LNode node = nodeIter.next();
        if (node.getProperty(LayeredOptions.COMMENT_BOX)) {
            commentBoxCount++;
            int edgeCount = 0;
            LEdge edge = null;
            LPort oppositePort = null;
            for (LPort port : node.getPorts()) {
                edgeCount += port.getDegree();
                if (port.getIncomingEdges().size() == 1) {
                    edge = port.getIncomingEdges().get(0);
                    oppositePort = edge.getSource();
                }
                if (port.getOutgoingEdges().size() == 1) {
                    edge = port.getOutgoingEdges().get(0);
                    oppositePort = edge.getTarget();
                }
            }
            if (edgeCount == 1 && oppositePort.getDegree() == 1 && !oppositePort.getNode().getProperty(LayeredOptions.COMMENT_BOX)) {
                // found a comment that has exactly one connection
                processBox(node, edge, oppositePort, oppositePort.getNode());
                nodeIter.remove();
            } else {
                // reverse edges that are oddly connected
                List<LEdge> revEdges = Lists.newArrayList();
                for (LPort port : node.getPorts()) {
                    for (LEdge outedge : port.getOutgoingEdges()) {
                        if (!outedge.getTarget().getOutgoingEdges().isEmpty()) {
                            revEdges.add(outedge);
                        }
                    }
                    for (LEdge inedge : port.getIncomingEdges()) {
                        if (!inedge.getSource().getIncomingEdges().isEmpty()) {
                            revEdges.add(inedge);
                        }
                    }
                }
                for (LEdge re : revEdges) {
                    re.reverse(layeredGraph, true);
                }
            }
        }
    }
    if (monitor.isLoggingEnabled()) {
        monitor.log("Found " + commentBoxCount + " comment boxes");
    }
    monitor.done();
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode)

Example 47 with LEdge

use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.

the class CompoundGraphPreprocessor method moveLabelsAndRemoveOriginalEdges.

/**
 * Moves all labels of the original edges to the appropriate dummy edges and removes the
 * original edges from the graph.
 *
 * @param graph
 *            the top-level graph.
 */
private void moveLabelsAndRemoveOriginalEdges(final LGraph graph) {
    // edges from the graph
    for (LEdge origEdge : crossHierarchyMap.keySet()) {
        // segments
        if (origEdge.getLabels().size() > 0) {
            // retrieve and sort the edge segments introduced for the original edge
            List<CrossHierarchyEdge> edgeSegments = new ArrayList<CrossHierarchyEdge>(crossHierarchyMap.get(origEdge));
            Collections.sort(edgeSegments, new CrossHierarchyEdgeComparator(graph));
            // iterate over the labels and move them to the edge segments
            Iterator<LLabel> labelIterator = origEdge.getLabels().listIterator();
            while (labelIterator.hasNext()) {
                LLabel currLabel = labelIterator.next();
                // find the index of the dummy edge we will move the label to
                int targetDummyEdgeIndex = -1;
                switch(currLabel.getProperty(LayeredOptions.EDGE_LABELS_PLACEMENT)) {
                    case HEAD:
                        targetDummyEdgeIndex = edgeSegments.size() - 1;
                        break;
                    case CENTER:
                        targetDummyEdgeIndex = getShallowestEdgeSegment(edgeSegments);
                        break;
                    case TAIL:
                        targetDummyEdgeIndex = 0;
                        break;
                    default:
                }
                // move the label if we were lucky enough to find a new home for it
                if (targetDummyEdgeIndex != -1) {
                    CrossHierarchyEdge targetSegment = edgeSegments.get(targetDummyEdgeIndex);
                    targetSegment.getEdge().getLabels().add(currLabel);
                    targetSegment.getEdge().getSource().getNode().getGraph().getProperty(InternalProperties.GRAPH_PROPERTIES).add(GraphProperties.END_LABELS);
                    targetSegment.getEdge().getSource().getNode().getGraph().getProperty(InternalProperties.GRAPH_PROPERTIES).add(GraphProperties.CENTER_LABELS);
                    labelIterator.remove();
                    currLabel.setProperty(InternalProperties.ORIGINAL_LABEL_EDGE, origEdge);
                }
            }
        }
        // remove original edge
        origEdge.setSource(null);
        origEdge.setTarget(null);
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LEdge(org.eclipse.elk.alg.layered.graph.LEdge) ArrayList(java.util.ArrayList)

Example 48 with LEdge

use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.

the class CompoundGraphPreprocessor method connectSiblings.

/**
 * Connects external ports of two child nodes of the given graph. To this end, the provided list
 * of external ports is searched for the counterpart of the provided external output port, and a
 * new dummy edge is created to connect the two. The dummy edge is associated with the original
 * hierarchy-crossing edge in the cross hierarchy map.
 *
 * @param graph
 *            the graph whose child nodes to connect.
 * @param externalOutputPort
 *            the external output port.
 * @param containedExternalPorts
 *            list of external ports exposed by children of the graph. This list is searched for
 *            the external target port.
 * @param origEdge
 *            the original edge that is being broken.
 */
private void connectSiblings(final LGraph graph, final ExternalPort externalOutputPort, final List<ExternalPort> containedExternalPorts, final LEdge origEdge) {
    // find the opposite external port
    ExternalPort targetExternalPort = null;
    for (ExternalPort externalPort2 : containedExternalPorts) {
        if (externalPort2 != externalOutputPort && externalPort2.origEdges.contains(origEdge)) {
            targetExternalPort = externalPort2;
            break;
        }
    }
    assert targetExternalPort.type == PortType.INPUT;
    // add new dummy edge and connect properly
    LEdge dummyEdge = createDummyEdge(graph, origEdge);
    dummyEdge.setSource(externalOutputPort.dummyPort);
    dummyEdge.setTarget(targetExternalPort.dummyPort);
    crossHierarchyMap.put(origEdge, new CrossHierarchyEdge(dummyEdge, graph, externalOutputPort.type));
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge)

Example 49 with LEdge

use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.

the class CompoundGraphPreprocessor method introduceHierarchicalEdgeSegment.

// //////////////////////////////////////////////////////////////////////////////////////////
// General Hierarchical Edge Segment Processing
/**
 * Does the actual work of creating a new hierarchical edge segment between an external port and
 * a given opposite port. The external port used for the segment is returned. This method does
 * not put any created edges into the cross hierarchy map!
 *
 * <p>
 * The method first decides on an external port to use for the segment. If the default external
 * port passed to the method is not {@code null} and if external ports are to be merged in the
 * current graph, the default external port is reused. An exception are segments that start or
 * end in the parent node; each such segments gets its own external port.
 * </p>
 *
 * <p>
 * If a new external port is created, the method also creates a dummy node for it as well as an
 * actual port on the parent node, if no such port already exists, as well as a dummy edge for
 * the connection. Thus, the newly created external port has everything it needs to be properly
 * represented and initialized.
 * </p>
 *
 * <p>
 * The original edge is added to the list of original edges in the external port used for the
 * segment. The dummy edge is associated with the original hierarchy-crossing edge in the cross
 * hierarchy map.
 * </p>
 *
 * @param graph
 *            the layered graph.
 * @param parentNode
 *            the graph's parent node, or {@code null} if the graph is at the top level.
 * @param origEdge
 *            the hierarchy-crossing edge that is being broken.
 * @param oppositePort
 *            the port that will be one of the two end points of the new segment.
 * @param portType
 *            the type of the port to create as one of the segment's edge points.
 * @param defaultExternalPort
 *            a default external port we can reuse if external ports should be merged. If this
 *            is {@code null}, a new external port is always created. If this port is reused, it
 *            is returned by this method.
 * @return the (created or reused) external port used as one endpoint of the edge segment.
 */
private ExternalPort introduceHierarchicalEdgeSegment(final LGraph graph, final LNode parentNode, final LEdge origEdge, final LPort oppositePort, final PortType portType, final ExternalPort defaultExternalPort) {
    // check if external ports are to be merged
    boolean mergeExternalPorts = graph.getProperty(LayeredOptions.MERGE_HIERARCHY_EDGES);
    // check if the edge connects to the parent node instead of to the outside world; if so, the
    // parentEndPort will be non-null
    LPort parentEndPort = null;
    if (portType == PortType.INPUT && origEdge.getSource().getNode() == parentNode) {
        parentEndPort = origEdge.getSource();
    } else if (portType == PortType.OUTPUT && origEdge.getTarget().getNode() == parentNode) {
        parentEndPort = origEdge.getTarget();
    }
    // only create a new external port if the current one is null or if ports are not to be merged
    // or if the connection actually ends at the parent node
    ExternalPort externalPort = defaultExternalPort;
    if (externalPort == null || !mergeExternalPorts || parentEndPort != null) {
        // create a dummy node that will represent the external port
        PortSide externalPortSide = PortSide.UNDEFINED;
        if (parentEndPort != null) {
            externalPortSide = parentEndPort.getSide();
        } else {
            // for people to set compound node port constraints to FREE
            if (parentNode.getProperty(LayeredOptions.PORT_CONSTRAINTS).isSideFixed()) {
                externalPortSide = portType == PortType.INPUT ? PortSide.WEST : PortSide.EAST;
            }
        }
        LNode dummyNode = createExternalPortDummy(graph, parentNode, portType, externalPortSide, origEdge);
        // create a dummy edge to be connected to the port
        LEdge dummyEdge = createDummyEdge(parentNode.getGraph(), origEdge);
        if (portType == PortType.INPUT) {
            // if the external port is an input port, the source of the edge must be connected to
            // the new dummy node
            dummyEdge.setSource(dummyNode.getPorts().get(0));
            dummyEdge.setTarget(oppositePort);
        } else {
            // if the external port is an output port, the target of the edge must be connected to
            // the new dummy node
            dummyEdge.setSource(oppositePort);
            dummyEdge.setTarget(dummyNode.getPorts().get(0));
        }
        // create the external port (the port is to be exported if the connection is not just to the
        // parent node)
        externalPort = new ExternalPort(origEdge, dummyEdge, dummyNode, (LPort) dummyNode.getProperty(InternalProperties.ORIGIN), portType, parentEndPort == null);
    } else {
        // we use an existing external port, so simply add the original edge to its list of
        // original edges
        externalPort.origEdges.add(origEdge);
        // merge the properties of the original edges
        double thickness = Math.max(externalPort.newEdge.getProperty(LayeredOptions.EDGE_THICKNESS), origEdge.getProperty(LayeredOptions.EDGE_THICKNESS));
        externalPort.newEdge.setProperty(LayeredOptions.EDGE_THICKNESS, thickness);
    }
    crossHierarchyMap.put(origEdge, new CrossHierarchyEdge(externalPort.newEdge, graph, portType));
    return externalPort;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode) PortSide(org.eclipse.elk.core.options.PortSide)

Example 50 with LEdge

use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.

the class DummySelfLoopProcessor method createDummy.

/**
 * Creates a dummy for the self-loop edge connecting the two given ports. The dummy is not
 * added to the layer yet.
 *
 * @param layeredGraph the layered graph.
 * @param edge the self-looping edge.
 * @param sourcePort the source port.
 * @param targetPort the target port.
 * @return the dummy node created.
 */
private LNode createDummy(final LGraph layeredGraph, final LEdge edge, final LPort sourcePort, final LPort targetPort) {
    // Create a dummy node with an input port and an output port
    LNode dummyNode = new LNode(layeredGraph);
    dummyNode.setType(NodeType.LONG_EDGE);
    dummyNode.setProperty(InternalProperties.ORIGIN, edge);
    dummyNode.setProperty(LayeredOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
    dummyNode.setProperty(InternalProperties.LONG_EDGE_SOURCE, sourcePort);
    dummyNode.setProperty(InternalProperties.LONG_EDGE_TARGET, targetPort);
    LPort dummyInput = new LPort();
    dummyInput.setSide(PortSide.WEST);
    dummyInput.setNode(dummyNode);
    LPort dummyOutput = new LPort();
    dummyOutput.setSide(PortSide.EAST);
    dummyOutput.setNode(dummyNode);
    edge.setTarget(dummyInput);
    // Create a dummy edge
    LEdge dummyEdge = new LEdge();
    dummyEdge.copyProperties(edge);
    dummyEdge.setProperty(LayeredOptions.JUNCTION_POINTS, null);
    dummyEdge.setSource(dummyOutput);
    dummyEdge.setTarget(targetPort);
    return dummyNode;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) LPort(org.eclipse.elk.alg.layered.graph.LPort) LNode(org.eclipse.elk.alg.layered.graph.LNode)

Aggregations

LEdge (org.eclipse.elk.alg.layered.graph.LEdge)148 LNode (org.eclipse.elk.alg.layered.graph.LNode)107 LPort (org.eclipse.elk.alg.layered.graph.LPort)80 Layer (org.eclipse.elk.alg.layered.graph.Layer)41 KVector (org.eclipse.elk.core.math.KVector)34 KVectorChain (org.eclipse.elk.core.math.KVectorChain)20 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)17 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)16 PortSide (org.eclipse.elk.core.options.PortSide)11 ArrayList (java.util.ArrayList)9 List (java.util.List)9 InternalProperties (org.eclipse.elk.alg.layered.options.InternalProperties)8 Set (java.util.Set)7 LayeredOptions (org.eclipse.elk.alg.layered.options.LayeredOptions)7 Map (java.util.Map)6 IElkProgressMonitor (org.eclipse.elk.core.util.IElkProgressMonitor)6 Lists (com.google.common.collect.Lists)5 Iterator (java.util.Iterator)5 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)5 Pair (org.eclipse.elk.core.util.Pair)5