use of org.eclipse.elk.alg.layered.compaction.oned.CGroup in project elk by eclipse.
the class OneDimensionalComponentsCompaction method compact.
/**
* Internal compaction method, performs 3 compactions into each direction (horizontal first,
* then vertical). The first compaction is unconstrained, the latter two consider the node locks.
*/
private double compact(final int run) {
double delta = 0;
// reset all groups' deltas
for (CGroup g : compactionGraph.cGroups) {
g.delta = 0;
g.deltaNormalized = 0;
}
// ----------------------------------------------------
// #1 We want to perform horizontal compaction first.
// For this we have to add the vertical external
// edges to the hulls to prevent edge node overlaps
// ----------------------------------------------------
addPlaceholders(Dir.HORZ);
addExternalEdgeRepresentations(verticalExternalExtensions);
compactor.calculateGroupOffsets();
// there are new nodes in the compaction graph, we have to update the constraints
compactor.forceConstraintsRecalculation();
Direction direction = Direction.LEFT;
// compact horizontally
compactor.changeDirection(direction).compact().changeDirection(direction.opposite()).applyLockingStrategy().compact().changeDirection(direction).applyLockingStrategy().compact();
// very important to transform back to LEFT
// because the hitboxes representing external edges
// that will be added in a second have not been transformed yet
compactor.changeDirection(Direction.LEFT);
// remove the vertical external edges again
removeExternalEdgeRepresentations(verticalExternalExtensions);
removePlaceholders(Dir.HORZ);
// .. and offset the horizontal external edges (that will be added next)
// according to the just finished horizontal compaction
updateExternalExtensionDimensions(Dir.HORZ);
updatePlaceholders(Dir.VERT);
// ----------------------------------------------------
// #2 We want to perform vertical compaction.
// ----------------------------------------------------
// now add them
addPlaceholders(Dir.VERT);
addExternalEdgeRepresentations(horizontalExternalExtensions);
compactor.calculateGroupOffsets();
// remember delta from horizontal compaction
for (CGroup g : compactionGraph.cGroups) {
delta += Math.abs(g.deltaNormalized);
}
// reset all groups' deltas
for (CGroup g : compactionGraph.cGroups) {
g.delta = 0;
g.deltaNormalized = 0;
}
direction = Direction.UP;
// compact vertically
compactor.changeDirection(direction).forceConstraintsRecalculation().compact().changeDirection(direction.opposite()).applyLockingStrategy().compact().changeDirection(direction).applyLockingStrategy().compact();
// transform back to LEFT
compactor.changeDirection(Direction.LEFT);
// remove the horizontal external edges
removeExternalEdgeRepresentations(horizontalExternalExtensions);
removePlaceholders(Dir.VERT);
// ... offset the vertical external edges
// (which have been excluded during the last compaction)
updateExternalExtensionDimensions(Dir.VERT);
updatePlaceholders(Dir.HORZ);
compactor.forceConstraintsRecalculation();
// ... and the delta from vertical compaction
for (CGroup g : compactionGraph.cGroups) {
delta += Math.abs(g.deltaNormalized);
}
return delta;
}
use of org.eclipse.elk.alg.layered.compaction.oned.CGroup in project elk by eclipse.
the class OneDimensionalComponentsCompaction method removePlaceholders.
private void removePlaceholders(final Dir dir) {
Set<Direction> dirs = (dir == Dir.VERT) ? UP_DOWN : LEFT_RIGHT;
for (Direction d : dirs) {
for (Pair<CGroup, CNode> pair : transformer.getExternalPlaceholder().get(d)) {
compactionGraph.cNodes.remove(pair.getSecond());
compactionGraph.cGroups.remove(pair.getSecond().cGroup);
}
}
}
use of org.eclipse.elk.alg.layered.compaction.oned.CGroup in project elk by eclipse.
the class LongestPathCompaction method compact.
@Override
public void compact(final OneDimensionalCompactor compactor) {
// calculating the left-most position of any element
// this will be our starting point for the compaction
double minStartPos = Double.POSITIVE_INFINITY;
for (CNode cNode : compactor.cGraph.cNodes) {
minStartPos = Math.min(minStartPos, cNode.cGroup.reference.hitbox.x + cNode.cGroupOffset.x);
}
// finding the sinks of the constraint graph
Queue<CGroup> sinks = Lists.newLinkedList();
for (CGroup group : compactor.cGraph.cGroups) {
group.startPos = minStartPos;
if (group.outDegree == 0) {
sinks.add(group);
}
}
// process sinks until every node in the constraint graph was handled
while (!sinks.isEmpty()) {
CGroup group = sinks.poll();
// record the movement of this group during the current compaction
// this has to be recorded _before_ the nodes' positions are updated
// and care has to be taken about the compaction direction. In certain
// scenarios nodes may move "back-and-forth". To detect this, we associate
// a negative delta with two of the compaction directions.
double diff = group.reference.hitbox.x;
// ------------------------------------------
for (CNode node : group.cNodes) {
// CNodes can be locked in place to avoid pulling clusters apart
double suggestedX = group.startPos + node.cGroupOffset.x;
if (// node.reposition
node.cGroup.reposition || // does the "fixed" position violate the constraints?
(node.getPosition() < suggestedX)) {
node.startPos = suggestedX;
} else {
// leave the node where it was!
node.startPos = node.hitbox.x;
}
}
diff -= group.reference.startPos;
group.delta += diff;
if (compactor.direction == Direction.RIGHT || compactor.direction == Direction.DOWN) {
group.deltaNormalized += diff;
} else {
group.deltaNormalized -= diff;
}
// ---------------------------------------------------
for (CNode node : group.cNodes) {
for (CNode incNode : node.constraints) {
// determine the required spacing
double spacing;
if (compactor.direction.isHorizontal()) {
spacing = compactor.spacingsHandler.getHorizontalSpacing(node, incNode);
} else {
spacing = compactor.spacingsHandler.getVerticalSpacing(node, incNode);
}
incNode.cGroup.startPos = Math.max(incNode.cGroup.startPos, node.startPos + node.hitbox.width + spacing - // respect the other group's node's offset
incNode.cGroupOffset.x);
// whether the node's current position should be preserved
if (!incNode.reposition) {
incNode.cGroup.startPos = Math.max(incNode.cGroup.startPos, incNode.getPosition() - incNode.cGroupOffset.x);
}
incNode.cGroup.outDegree--;
if (incNode.cGroup.outDegree == 0) {
sinks.add(incNode.cGroup);
}
}
}
}
// ------------------------------------------------------
for (CNode cNode : compactor.cGraph.cNodes) {
cNode.applyPosition();
}
}
use of org.eclipse.elk.alg.layered.compaction.oned.CGroup in project elk by eclipse.
the class ComponentsToCGraphTransformer method applyLayout.
/* -----------------------------------------------------------
* Layout Application
* ----------------------------------------------------------- */
@Override
public void applyLayout() {
for (CNode n : cGraph.cNodes) {
n.applyElementPosition();
}
// calculating new graph size and offset
KVector topLeft = new KVector(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
KVector bottomRight = new KVector(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
for (CNode cNode : cGraph.cNodes) {
topLeft.x = Math.min(topLeft.x, cNode.hitbox.x);
topLeft.y = Math.min(topLeft.y, cNode.hitbox.y);
bottomRight.x = Math.max(bottomRight.x, cNode.hitbox.x + cNode.hitbox.width);
bottomRight.y = Math.max(bottomRight.y, cNode.hitbox.y + cNode.hitbox.height);
}
// which allows to use them to determine the maximum position
for (Pair<CGroup, CNode> placeholder : externalPlaceholder.values()) {
CNode cNode = placeholder.getSecond();
topLeft.x = Math.min(topLeft.x, cNode.hitbox.x);
topLeft.y = Math.min(topLeft.y, cNode.hitbox.y);
bottomRight.x = Math.max(bottomRight.x, cNode.hitbox.x + cNode.hitbox.width);
bottomRight.y = Math.max(bottomRight.y, cNode.hitbox.y + cNode.hitbox.height);
}
globalOffset = topLeft.clone().negate();
graphSize = bottomRight.clone().sub(topLeft);
// resetting lists
cGraph.cGroups.clear();
cGraph.cNodes.clear();
}
use of org.eclipse.elk.alg.layered.compaction.oned.CGroup in project elk by eclipse.
the class OneDimensionalComponentsCompaction method updateExternalExtensionDimensions.
/**
* During compaction of the x dimension the horizontal external extensions are not part of the
* graph that is being compacted. As a consequence, their positions are not updated. We make up
* for this in this method. Additionally, the dimensions of the diagram are respected and
* external extensions are guaranteed to always extend to the very border of the diagram
* (preventing components from overlapping with edges).
*
* @param dir
* whether to update the vertical or the horizontal extensions.
*/
private void updateExternalExtensionDimensions(final Dir dir) {
for (Entry<IExternalExtension<E>, Pair<CGroup, CNode>> entry : transformer.getExternalExtensions().entrySet()) {
IExternalExtension<E> ee = entry.getKey();
if (dir == Dir.VERT) {
if (ee.getDirection() != Direction.UP && ee.getDirection() != Direction.DOWN) {
continue;
}
} else {
if (ee.getDirection() != Direction.LEFT && ee.getDirection() != Direction.RIGHT) {
continue;
}
}
CNode cNode = entry.getValue().getSecond();
// the node may not be associated with the group atm, thus cNode.group may be null
CGroup group = entry.getValue().getFirst();
// deltaNormalized is negative if a group was moved to the left,
// positive if the group was moved to the right
double adelta = group.deltaNormalized;
switch(ee.getDirection()) {
case LEFT:
// x sticks to the left of the diagram
cNode.hitbox.x = topLeft.x;
cNode.hitbox.width = Math.max(1, cNode.hitbox.width + adelta);
break;
case RIGHT:
cNode.hitbox.x = cNode.hitbox.x + adelta;
cNode.hitbox.width = Math.max(1, cNode.hitbox.width - adelta);
break;
case UP:
// y sticks to the top of the diagram
cNode.hitbox.y = topLeft.y;
cNode.hitbox.height = Math.max(1, cNode.hitbox.height + adelta);
break;
case DOWN:
cNode.hitbox.y = cNode.hitbox.y + adelta;
cNode.hitbox.height = Math.max(1, cNode.hitbox.height - adelta);
break;
}
}
}
Aggregations