/** {@inheritDoc} */ public void process(final LGraph layeredGraph, final IKielerProgressMonitor monitor) { monitor.begin("Comment pre-processing", 1); Iterator<LNode> nodeIter = layeredGraph.getLayerlessNodes().iterator(); while (nodeIter.hasNext()) { LNode node = nodeIter.next(); if (node.getProperty(LayoutOptions.COMMENT_BOX)) { 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(LayoutOptions.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); } } } } monitor.done(); }
/** * Process a comment box by putting it into a property of the corresponding node. * * @param box a comment box * @param edge the edge that connects the box with the real node * @param oppositePort the port of the real node to which the edge is incident * @param realNode the normal node that is connected with the comment */ private void processBox( final LNode box, final LEdge edge, final LPort oppositePort, final LNode realNode) { boolean topFirst, onlyTop = false, onlyBottom = false; if (realNode.getProperty(LayoutOptions.PORT_CONSTRAINTS).isSideFixed()) { boolean hasNorth = false, hasSouth = false; portLoop: for (LPort port1 : realNode.getPorts()) { for (LPort port2 : port1.getConnectedPorts()) { if (!port2.getNode().getProperty(LayoutOptions.COMMENT_BOX)) { if (port1.getSide() == PortSide.NORTH) { hasNorth = true; break portLoop; } if (port1.getSide() == PortSide.SOUTH) { hasSouth = true; break portLoop; } } } } onlyTop = hasSouth && !hasNorth; onlyBottom = hasNorth && !hasSouth; } if (!onlyTop && !onlyBottom && !realNode.getLabels().isEmpty()) { double labelPos = 0; for (LLabel label : realNode.getLabels()) { labelPos += label.getPosition().y + label.getSize().y / 2; } labelPos /= realNode.getLabels().size(); topFirst = labelPos >= realNode.getSize().y / 2; } else { topFirst = !onlyBottom; } List<LNode> boxList; if (topFirst) { // determine the position to use, favoring the top position List<LNode> topBoxes = realNode.getProperty(InternalProperties.TOP_COMMENTS); if (topBoxes == null) { boxList = Lists.newArrayList(); realNode.setProperty(InternalProperties.TOP_COMMENTS, boxList); } else if (onlyTop) { boxList = topBoxes; } else { List<LNode> bottomBoxes = realNode.getProperty(InternalProperties.BOTTOM_COMMENTS); if (bottomBoxes == null) { boxList = Lists.newArrayList(); realNode.setProperty(InternalProperties.BOTTOM_COMMENTS, boxList); } else { if (topBoxes.size() <= bottomBoxes.size()) { boxList = topBoxes; } else { boxList = bottomBoxes; } } } } else { // determine the position to use, favoring the bottom position List<LNode> bottomBoxes = realNode.getProperty(InternalProperties.BOTTOM_COMMENTS); if (bottomBoxes == null) { boxList = Lists.newArrayList(); realNode.setProperty(InternalProperties.BOTTOM_COMMENTS, boxList); } else if (onlyBottom) { boxList = bottomBoxes; } else { List<LNode> topBoxes = realNode.getProperty(InternalProperties.TOP_COMMENTS); if (topBoxes == null) { boxList = Lists.newArrayList(); realNode.setProperty(InternalProperties.TOP_COMMENTS, boxList); } else { if (bottomBoxes.size() <= topBoxes.size()) { boxList = bottomBoxes; } else { boxList = topBoxes; } } } } // add the comment box to one of the two possible lists boxList.add(box); // set the opposite port as property for the comment box box.setProperty(InternalProperties.COMMENT_CONN_PORT, oppositePort); // detach the edge and the opposite port if (edge.getTarget() == oppositePort) { edge.setTarget(null); if (oppositePort.getDegree() == 0) { oppositePort.setNode(null); } } else { edge.setSource(null); if (oppositePort.getDegree() == 0) { oppositePort.setNode(null); } } edge.getBendPoints().clear(); }
/** * Collects the positions and dimensions of {@link LNode}s and vertical segments in the layered * graph and writes them to the {@link CNode}s. */ private void readNodes() { List<VerticalSegment> verticalSegments = Lists.newArrayList(); // resetting to avoid problems if this is called repeatedly cGraph.cNodes.clear(); // 1. collecting positions of graph elements for (Layer layer : layeredGraph) { for (LNode node : layer) { // add all nodes CLNode cNode = new CLNode(node, layeredGraph); cGraph.cNodes.add(cNode); // add vertical edge segments for (LEdge edge : node.getOutgoingEdges()) { Iterator<KVector> bends = edge.getBendPoints().iterator(); // infer vertical segments from positions of bendpoints if (bends.hasNext()) { KVector bend1 = bends.next(); // get segment of source n/s port if (edge.getSource().getSide() == PortSide.NORTH || edge.getSource().getSide() == PortSide.SOUTH) { verticalSegments.add( new VerticalSegment(bend1, edge.getSource().getAbsoluteAnchor(), cNode, edge)); } // get regular segments while (bends.hasNext()) { KVector bend2 = bends.next(); if (!CompareFuzzy.eq(bend1.y, bend2.y)) { verticalSegments.add(new VerticalSegment(bend1, bend2, null, edge)); } bend1 = bend2; } } } // same for incoming edges to get NSSegments on target side for (LEdge edge : node.getIncomingEdges()) { if (!edge.getBendPoints().isEmpty()) { // get segment of target n/s port if (edge.getTarget().getSide() == PortSide.NORTH || edge.getTarget().getSide() == PortSide.SOUTH) { KVector bend1 = edge.getBendPoints().getLast(); verticalSegments.add( new VerticalSegment(bend1, edge.getTarget().getAbsoluteAnchor(), cNode, edge)); } } } } } // 2. combining intersecting segments in CLEdges to process them as one if (!verticalSegments.isEmpty()) { // sorting the segments by position in ascending order Collections.sort(verticalSegments); // merging intersecting segments in the same CLEdge VerticalSegment last = verticalSegments.get(0); CLEdge c = new CLEdge(last, layeredGraph); for (int i = 1; i < verticalSegments.size(); i++) { VerticalSegment verticalSegment = verticalSegments.get(i); if (verticalSegment.intersects(last)) { c.addSegment(verticalSegment); } else { cGraph.cNodes.add(c); c = new CLEdge(verticalSegment, layeredGraph); } last = verticalSegment; } cGraph.cNodes.add(c); } verticalSegments.clear(); // 3. grouping nodes with their connected north/south segments groupCNodes(); }