use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class AbstractGraphPlacer method moveGraph.
/**
* Move the source graph into the destination graph using a specified offset. This method should
* only be called once per graph, since it also applies the graph's set offset in addition to the
* one given in the methods of this argument.
*
* @param destGraph the destination graph.
* @param sourceGraph the source graph.
* @param offsetx x coordinate offset.
* @param offsety y coordinate offset.
*/
protected void moveGraph(final LGraph destGraph, final LGraph sourceGraph, final double offsetx, final double offsety) {
KVector graphOffset = sourceGraph.getOffset().add(offsetx, offsety);
for (LNode node : sourceGraph.getLayerlessNodes()) {
node.getPosition().add(graphOffset);
for (LPort port : node.getPorts()) {
for (LEdge edge : port.getOutgoingEdges()) {
edge.getBendPoints().offset(graphOffset);
KVectorChain junctionPoints = edge.getProperty(LayeredOptions.JUNCTION_POINTS);
if (junctionPoints != null) {
junctionPoints.offset(graphOffset);
}
for (LLabel label : edge.getLabels()) {
label.getPosition().add(graphOffset);
}
}
}
destGraph.getLayerlessNodes().add(node);
node.setGraph(destGraph);
}
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class EndLabelSorter method createLabelGroups.
/**
* Creates a list of {@link LabelGroup}s that group labels from the same edge.
*/
private List<LabelGroup> createLabelGroups(final LabelCell portLabelCell) {
Map<LEdge, LabelGroup> edgeToGroupMap = new HashMap<>();
// Make sure every label is contained in a label group
for (LabelAdapter<?> label : portLabelCell.getLabels()) {
LEdge edge = label.getProperty(InternalProperties.END_LABEL_EDGE);
// label didn't have an END_LABEL_EDGE property set
if (!edgeToGroupMap.containsKey(edge)) {
edgeToGroupMap.put(edge, new LabelGroup(edge));
}
edgeToGroupMap.get(edge).labels.add(label);
}
return new ArrayList<>(edgeToGroupMap.values());
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class FinalSplineBendpointsCalculator method calculateControlPoints.
/**
* The method dispatches the calculation of NUB control points for the passed {@code segment} to the
* {@code calculateControlPoints*(..)} methods based on the following criteria.
* <ul>
* <li>the desired {@link SplineRoutingMode}</li>
* <li>if the segment is straight</li>
* <li>if the segment represents an in-layer edge due to inverted ports</li>
* <li>if the segment represents a hyperedge</li>
* </ul>
*/
private void calculateControlPoints(final SplineSegment segment) {
// with hyperedges it can happen that this method is called multiple times for the same segment
if (segment.handled) {
return;
}
segment.handled = true;
for (final LEdge edge : segment.edges) {
if (segment.isStraight && !segment.isHyperEdge()) {
calculateControlPointsStraight(segment);
continue;
}
// Remember that the edge itself is not necessarily valid at this point
// (it may have been remove by the long edge joiner, for instance)
EdgeInformation ei = segment.edgeInformation.get(edge);
// inverted ports are handled in the same way for
if (ei.invertedLeft || ei.invertedRight) {
calculateControlPointsInvertedEdge(edge, segment);
continue;
}
// to compute sloppy control points at least one of the
// two nodes connected by the segment must be a 'normal' node,
// and in case horizontal compaction is active the predicate implemented
// by the 'segmentAllowsSloppyRouting(..)' method must be true
// for hyperedges sloppy routing is not possible
boolean sloppy = splineRoutingMode == SplineRoutingMode.SLOPPY && (ei.normalSourceNode || ei.normalTargetNode) && segmentAllowsSloppyRouting(segment) && !segment.isHyperEdge();
if (sloppy) {
calculateControlPointsSloppy(edge, segment);
} else {
calculateControlPointsConservative(edge, segment);
}
}
if (segment.inverseOrder) {
segment.edges.forEach(e -> Collections.reverse(e.getBendPoints()));
}
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class BKAligner method insideBlockShift.
/**
* This phase moves the nodes inside a block, ensuring that all edges inside a block can be drawn
* as straight lines. It is not included in the original algorithm and adds port and node size
* handling.
*
* @param bal One of the four layouts which shall be used in this step
*/
public void insideBlockShift(final BKAlignedLayout bal) {
Map<LNode, List<LNode>> blocks = getBlocks(bal);
for (LNode root : blocks.keySet()) {
// For each block, we place the top left corner of the root node at coordinate (0,0). We
// then calculate the space required above the top left corner (due to other nodes placed
// above and to top margins of nodes, including the root node) and the space required below
// the top left corner. The sum of both becomes the block size, and the y coordinate of each
// node relative to the block's top border becomes the inner shift of that node.
double spaceAbove = 0.0;
double spaceBelow = 0.0;
// Reserve space for the root node
spaceAbove = root.getMargin().top;
spaceBelow = root.getSize().y + root.getMargin().bottom;
bal.innerShift[root.id] = 0.0;
// Iterate over all other nodes of the block
LNode current = root;
LNode next;
while ((next = bal.align[current.id]) != root) {
// Find the edge between the current and the next node
LEdge edge = getEdge(current, next);
// Calculate the y coordinate difference between the two nodes required to straighten
// the edge
double portPosDiff = 0.0;
if (bal.hdir == HDirection.LEFT) {
portPosDiff = edge.getTarget().getPosition().y + edge.getTarget().getAnchor().y - edge.getSource().getPosition().y - edge.getSource().getAnchor().y;
} else {
portPosDiff = edge.getSource().getPosition().y + edge.getSource().getAnchor().y - edge.getTarget().getPosition().y - edge.getTarget().getAnchor().y;
}
// The current node already has an inner shift value that we need to use as the basis
// to calculate the next node's inner shift
double nextInnerShift = bal.innerShift[current.id] + portPosDiff;
bal.innerShift[next.id] = nextInnerShift;
// Update the space required above and below the root node's top left corner
spaceAbove = Math.max(spaceAbove, next.getMargin().top - nextInnerShift);
spaceBelow = Math.max(spaceBelow, nextInnerShift + next.getSize().y + next.getMargin().bottom);
// The next node is the current node in the next iteration
current = next;
}
// Adjust each node's inner shift by the space required above the root node's top left
// corner (which the inner shifts are relative to at the moment)
current = root;
do {
bal.innerShift[current.id] = bal.innerShift[current.id] + spaceAbove;
current = bal.align[current.id];
} while (current != root);
// Remember the block size
bal.blockSize[root.id] = spaceAbove + spaceBelow;
}
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class BKNodePlacer method markConflicts.
/**
* This phase of the node placer marks all type 1 and type 2 conflicts.
*
* <p>The conflict types base on the distinction of inner segments and non-inner segments of edges.
* A inner segment is present if an edge is drawn between two dummy nodes and thus is part of
* a long edge. A non-inner segment is present if one of the connected nodes is not a dummy
* node.</p>
*
* <p>Type 0 conflicts occur if two non-inner segments cross each other. Type 1 conflicts happen
* when a non-inner segment and a inner segment cross. Type 2 conflicts are present if two
* inner segments cross.</p>
*
* <p>The markers are later used to solve conflicts in favor of long edges. In case of type 2
* conflicts, the marker favors the earlier node in layout order.</p>
*
* @param layeredGraph The layered graph to be layouted
*/
private void markConflicts(final LGraph layeredGraph) {
int numberOfLayers = layeredGraph.getLayers().size();
// Check if there are enough layers to detect conflicts
if (numberOfLayers < MIN_LAYERS_FOR_CONFLICTS) {
return;
}
// We'll need the number of nodes in the different layers quite often in this method, so save
// them up front
int[] layerSize = new int[numberOfLayers];
int layerIndex = 0;
for (Layer layer : layeredGraph.getLayers()) {
layerSize[layerIndex++] = layer.getNodes().size();
}
// The following call succeeds since there are at least 3 layers in the graph
Iterator<Layer> layerIterator = layeredGraph.getLayers().listIterator(2);
for (int i = 1; i < numberOfLayers - 1; i++) {
// The variable naming here follows the notation of the corresponding paper
// Normally, underscores are not allowed in local variable names, but since there
// is no way of properly writing indices beside underscores, Checkstyle will be
// disabled here and in future methods containing indexed variables
// CHECKSTYLEOFF Local Variable Names
Layer currentLayer = layerIterator.next();
Iterator<LNode> nodeIterator = currentLayer.getNodes().iterator();
int k_0 = 0;
int l = 0;
for (int l_1 = 0; l_1 < layerSize[i + 1]; l_1++) {
// In the paper, l and i are indices for the layer and the position in the layer
// currentLayer.getNodes().get(l_1);
LNode v_l_i = nodeIterator.next();
if (l_1 == ((layerSize[i + 1]) - 1) || incidentToInnerSegment(v_l_i, i + 1, i)) {
int k_1 = layerSize[i] - 1;
if (incidentToInnerSegment(v_l_i, i + 1, i)) {
k_1 = ni.nodeIndex[ni.leftNeighbors.get(v_l_i.id).get(0).getFirst().id];
}
while (l <= l_1) {
LNode v_l = currentLayer.getNodes().get(l);
if (!incidentToInnerSegment(v_l, i + 1, i)) {
for (Pair<LNode, LEdge> upperNeighbor : ni.leftNeighbors.get(v_l.id)) {
int k = ni.nodeIndex[upperNeighbor.getFirst().id];
if (k < k_0 || k > k_1) {
// Marked edge can't return null here, because the upper neighbor
// relationship between v_l and upperNeighbor enforces the existence
// of at least one edge between the two nodes
markedEdges.add(upperNeighbor.getSecond());
}
}
}
l++;
}
k_0 = k_1;
}
}
// CHECKSTYLEON Local Variable Names
}
}
Aggregations