use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class ComponentsCompactor method createDummyNode.
private LNode createDummyNode(final LGraph graph) {
// to handle it properly, we give it a tiny little dummy rectangle
assert graph.getLayerlessNodes().size() == 1;
LNode extPortDummy = graph.getLayerlessNodes().get(0);
// create a small dummy node for the external port dummy
LNode dummy = new LNode(graph);
graph.getLayerlessNodes().add(dummy);
// reassemble the size of the external dummy but assure
// that no dimension is zero. Otherwise we may end up
// with dimension-less hull rectangles which causes
// the scanline to fail
dummy.getSize().x = Math.max(1, extPortDummy.getSize().x);
dummy.getSize().y = Math.max(1, extPortDummy.getSize().y);
// set the position such that it is on the proper side
// with respect to the dummy port
dummy.getPosition().x = extPortDummy.getPosition().x;
dummy.getPosition().y = extPortDummy.getPosition().y;
switch(extPortDummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
case WEST:
dummy.getPosition().x += 2;
break;
case NORTH:
dummy.getPosition().y += 2;
break;
case EAST:
dummy.getPosition().x -= 2;
break;
case SOUTH:
dummy.getPosition().y -= 2;
break;
}
// give the dummy a port and create an edge for it
LPort dummyPort = new LPort();
dummyPort.setNode(dummy);
LEdge dummyEdge = new LEdge();
LPort extPortDummyPort = extPortDummy.getPorts().get(0);
dummyEdge.setSource(extPortDummyPort);
dummyEdge.setTarget(dummyPort);
// position the dummy port such that the edge will be straight
dummyPort.getPosition().reset().add(extPortDummyPort.getPosition());
dummyPort.getAnchor().reset().add(extPortDummyPort.getAnchor());
return dummy;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class ComponentsCompactor method componentHullPoints.
private Hullpoints componentHullPoints(final LGraph graph) {
final Hullpoints pts = new Hullpoints();
for (LNode n : graph.getLayerlessNodes()) {
if (n.getType() == NodeType.EXTERNAL_PORT) {
continue;
}
// Note that labels of nodes are already part of a node's margins
// the same is true for ports and their labels
addLGraphElementBounds(pts, n, new KVector());
// add bend points of the edges
for (LEdge edge : n.getOutgoingEdges()) {
if (isExternalEdge(edge)) {
continue;
}
for (KVector bp : edge.getBendPoints()) {
KVector absolute = bp;
pts.add(new Point(absolute.x, absolute.y));
}
}
}
return pts;
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class ComponentsCompactor method compact.
// ------------------------------------------------------------------------------------------------
// public API
// ------------------------------------------------------------------------------------------------
/**
* @param graphs
* the components to be compacted
* @param originalGraphsSize
* the size of the overall graph as it is currently
* @param spacing
* the desired spacing to be preserved between any pair of components
*/
public void compact(final List<LGraph> graphs, final KVector originalGraphsSize, final double spacing) {
// determine the extreme points of the current diagram,
// we will reuse this 'frame' to cut external extensions at appropriate lengths
graphTopLeft = new KVector(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
graphBottomRight = new KVector(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
for (LGraph graph : graphs) {
for (LNode node : graph.getLayerlessNodes()) {
graphTopLeft.x = Math.min(graphTopLeft.x, node.getPosition().x - node.getMargin().left);
graphTopLeft.y = Math.min(graphTopLeft.y, node.getPosition().y - node.getMargin().top);
graphBottomRight.x = Math.max(graphBottomRight.x, node.getPosition().x + node.getSize().x + node.getMargin().right);
graphBottomRight.y = Math.max(graphBottomRight.y, node.getPosition().y + node.getSize().y + node.getMargin().bottom);
}
}
// from the lgraphs, create connected components
IConnectedComponents<LNode, Set<LEdge>> ccs = new InternalConnectedComponents();
for (LGraph graph : graphs) {
IComponent<LNode, Set<LEdge>> c = transformLGraph(graph);
ccs.getComponents().add(c);
((InternalComponent) c).containsRegularNodes |= !c.getExternalExtensionSides().isEmpty();
}
// for every component we create an element in the compactor
compactor = OneDimensionalComponentsCompaction.init(ccs, spacing);
// execute compaction
compactor.compact(new BasicProgressMonitor());
yetAnotherOffset = new KVector();
compactedGraphSize = compactor.getGraphSize();
// apply the positions
for (IComponent<LNode, Set<LEdge>> cc : ccs.getComponents()) {
// retrieve the common offset for the currently handled connected component
KVector offset = compactor.getOffset(cc);
// move it
LGraphUtil.offsetGraph(((InternalComponent) cc).graph, offset.x, offset.y);
// adjust positions of external ports
for (LNode n : ((InternalComponent) cc).getNodes()) {
if (n.getType() == NodeType.EXTERNAL_PORT) {
KVector newPos = getExternalPortPosition(n.getPosition(), n.getProperty(InternalProperties.EXT_PORT_SIDE));
n.getPosition().reset().add(newPos);
}
}
}
// external edges contribute to the graph's size ... however, only certain segments do.
for (IComponent<LNode, Set<LEdge>> cc : ccs.getComponents()) {
for (LEdge e : ((InternalComponent) cc).getExternalEdges()) {
KVectorChain vc = new KVectorChain(e.getBendPoints());
vc.add(0, e.getSource().getAbsoluteAnchor());
vc.add(e.getTarget().getAbsoluteAnchor());
KVector last = null;
for (KVector v : vc) {
if (last == null) {
last = v;
continue;
}
if (DoubleMath.fuzzyEquals(last.x, v.x, EPSILON)) {
yetAnotherOffset.x = Math.min(yetAnotherOffset.x, last.x);
compactedGraphSize.x = Math.max(compactedGraphSize.x, last.x);
} else if (DoubleMath.fuzzyEquals(last.y, v.y, EPSILON)) {
yetAnotherOffset.y = Math.min(yetAnotherOffset.y, last.y);
compactedGraphSize.y = Math.max(compactedGraphSize.y, last.y);
}
last = v;
}
}
}
yetAnotherOffset.negate();
compactedGraphSize.add(yetAnotherOffset);
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class CompoundGraphPostprocessor method process.
@Override
public void process(final LGraph graph, final IElkProgressMonitor monitor) {
monitor.begin("Compound graph postprocessor", 1);
// whether bend points should be added whenever crossing a hierarchy boundary
boolean addUnnecessaryBendpoints = graph.getProperty(LayeredOptions.UNNECESSARY_BENDPOINTS);
// restore the cross-hierarchy map that was built by the preprocessor
Multimap<LEdge, CrossHierarchyEdge> crossHierarchyMap = graph.getProperty(InternalProperties.CROSS_HIERARCHY_MAP);
// remember all dummy edges we encounter; these need to be removed at the end
Set<LEdge> dummyEdges = Sets.newHashSet();
// iterate over all original edges
for (LEdge origEdge : crossHierarchyMap.keySet()) {
// find all cross-hierarchy edges the original edge was split into, and sort them from source to target
List<CrossHierarchyEdge> crossHierarchyEdges = new ArrayList<CrossHierarchyEdge>(crossHierarchyMap.get(origEdge));
Collections.sort(crossHierarchyEdges, new CrossHierarchyEdgeComparator(graph));
// find the original source and target ports for the original edge
LPort sourcePort = crossHierarchyEdges.get(0).getActualSource();
LPort targetPort = crossHierarchyEdges.get(crossHierarchyEdges.size() - 1).getActualTarget();
// determine the reference graph for all bend points
LNode referenceNode = sourcePort.getNode();
LGraph referenceGraph;
if (LGraphUtil.isDescendant(targetPort.getNode(), referenceNode)) {
referenceGraph = referenceNode.getNestedGraph();
} else {
referenceGraph = referenceNode.getGraph();
}
// check whether there are any junction points
KVectorChain junctionPoints = clearJunctionPoints(origEdge, crossHierarchyEdges);
// reset bend points (we have computed new ones anyway)
origEdge.getBendPoints().clear();
// apply the computed layouts to the cross-hierarchy edge
KVector lastPoint = null;
for (CrossHierarchyEdge chEdge : crossHierarchyEdges) {
// transform all coordinates from the graph of the dummy edge to the reference graph
KVector offset = new KVector();
LGraphUtil.changeCoordSystem(offset, chEdge.getGraph(), referenceGraph);
LEdge ledge = chEdge.getEdge();
KVectorChain bendPoints = new KVectorChain();
bendPoints.addAllAsCopies(0, ledge.getBendPoints());
bendPoints.offset(offset);
// Note: if an NPE occurs here, that means ELK Layered has replaced the original edge
KVector sourcePoint = new KVector(ledge.getSource().getAbsoluteAnchor());
KVector targetPoint = new KVector(ledge.getTarget().getAbsoluteAnchor());
sourcePoint.add(offset);
targetPoint.add(offset);
if (lastPoint != null) {
KVector nextPoint;
if (bendPoints.isEmpty()) {
nextPoint = targetPoint;
} else {
nextPoint = bendPoints.getFirst();
}
// we add the source point as a bend point to properly connect the hierarchy levels
// either if the last point of the previous hierarchy edge segment is a certain
// level of tolerance away or if we are required to add unnecessary bend points
boolean xDiffEnough = Math.abs(lastPoint.x - nextPoint.x) > OrthogonalRoutingGenerator.TOLERANCE;
boolean yDiffEnough = Math.abs(lastPoint.y - nextPoint.y) > OrthogonalRoutingGenerator.TOLERANCE;
if ((!addUnnecessaryBendpoints && xDiffEnough && yDiffEnough) || (addUnnecessaryBendpoints && (xDiffEnough || yDiffEnough))) {
origEdge.getBendPoints().add(sourcePoint);
}
}
origEdge.getBendPoints().addAll(bendPoints);
if (bendPoints.isEmpty()) {
lastPoint = sourcePoint;
} else {
lastPoint = bendPoints.getLast();
}
// copy junction points
copyJunctionPoints(ledge, junctionPoints, offset);
// add offset to target port with a special property
if (chEdge.getActualTarget() == targetPort) {
if (targetPort.getNode().getGraph() != chEdge.getGraph()) {
// the target port is in a different coordinate system -- recompute the offset
offset = new KVector();
LGraphUtil.changeCoordSystem(offset, targetPort.getNode().getGraph(), referenceGraph);
}
origEdge.setProperty(InternalProperties.TARGET_OFFSET, offset);
}
// copy labels back to the original edge
copyLabelsBack(ledge, origEdge, referenceGraph);
// remember the dummy edge for later removal (dummy edges may be in use by several
// different original edges, which is why we cannot just go and remove it now)
dummyEdges.add(ledge);
}
// restore the original source port and target port
origEdge.setSource(sourcePort);
origEdge.setTarget(targetPort);
}
// remove the dummy edges from the graph (dummy ports and dummy nodes are retained)
for (LEdge dummyEdge : dummyEdges) {
dummyEdge.setSource(null);
dummyEdge.setTarget(null);
}
monitor.done();
}
use of org.eclipse.elk.alg.layered.graph.LEdge in project elk by eclipse.
the class ElkGraphLayoutTransferrer method applyLayout.
/**
* Applies the layout information contained in the given LGraph to the ElkGraph elements it was
* created from. All source ElkGraph elements are expected to be accessible through their LGraph
* counterparts through the {@link InternalProperties#ORIGIN} property.
*
* @param lgraph the LGraph whose layout information to apply.
*/
public void applyLayout(final LGraph lgraph) {
Object graphOrigin = lgraph.getProperty(InternalProperties.ORIGIN);
if (!(graphOrigin instanceof ElkNode)) {
return;
}
// The ElkNode that represents this graph in the original ElkGraph
ElkNode parentElkNode = (ElkNode) graphOrigin;
// The LNode that represents this graph in the upper hierarchy level, if any
LNode parentLNode = (LNode) lgraph.getParentNode();
// Get the offset to be added to all coordinates
KVector offset = new KVector(lgraph.getOffset());
// Adjust offset (and with it the positions) by the requested padding
LPadding lPadding = lgraph.getPadding();
offset.x += lPadding.left;
offset.y += lPadding.top;
// Set node padding, if it was computed during layout
final EnumSet<SizeOptions> sizeOptions = parentElkNode.getProperty(LayeredOptions.NODE_SIZE_OPTIONS);
if (sizeOptions.contains(SizeOptions.COMPUTE_PADDING)) {
ElkPadding padding = parentElkNode.getProperty(LayeredOptions.PADDING);
padding.setBottom(lPadding.bottom);
padding.setTop(lPadding.top);
padding.setLeft(lPadding.left);
padding.setRight(lPadding.right);
}
// Along the way, we collect the list of edges to be processed later
List<LEdge> edgeList = Lists.newArrayList();
// Process the nodes
for (LNode lnode : lgraph.getLayerlessNodes()) {
if (representsNode(lnode)) {
applyNodeLayout(lnode, offset);
} else if (representsExternalPort(lnode) && parentLNode == null) {
// We have an external port here on the top-most hierarchy level of the current (possibly
// hierarchical) layout run; set its position
ElkPort elkport = (ElkPort) lnode.getProperty(InternalProperties.ORIGIN);
KVector portPosition = LGraphUtil.getExternalPortPosition(lgraph, lnode, elkport.getWidth(), elkport.getHeight());
elkport.setLocation(portPosition.x, portPosition.y);
}
// correctly)
for (LPort port : lnode.getPorts()) {
port.getOutgoingEdges().stream().filter(edge -> !LGraphUtil.isDescendant(edge.getTarget().getNode(), lnode)).forEach(edge -> edgeList.add(edge));
}
}
// Collect edges that go from the current graph's representing LNode down into its descendants
if (parentLNode != null) {
for (LPort port : parentLNode.getPorts()) {
port.getOutgoingEdges().stream().filter(edge -> LGraphUtil.isDescendant(edge.getTarget().getNode(), parentLNode)).forEach(edge -> edgeList.add(edge));
}
}
// Iterate through all edges
EdgeRouting routing = parentElkNode.getProperty(LayeredOptions.EDGE_ROUTING);
for (LEdge ledge : edgeList) {
applyEdgeLayout(ledge, routing, offset, lPadding);
}
// Setup the parent node
applyParentNodeLayout(lgraph);
// Process nested subgraphs
for (LNode lnode : lgraph.getLayerlessNodes()) {
LGraph nestedGraph = lnode.getNestedGraph();
if (nestedGraph != null) {
applyLayout(nestedGraph);
}
}
}
Aggregations