Java tutorial
/******************************************************************************* * Copyright (c) 2016 Kiel University and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Kiel University - initial API and implementation *******************************************************************************/ package org.eclipse.elk.alg.layered.compaction.oned.algs; import java.util.Queue; import org.eclipse.elk.alg.layered.compaction.oned.CGroup; import org.eclipse.elk.alg.layered.compaction.oned.CNode; import org.eclipse.elk.alg.layered.compaction.oned.OneDimensionalCompactor; import org.eclipse.elk.core.options.Direction; import com.google.common.collect.Lists; /** * Compacts a previously calculated constraint graph ( * {@link de.cau.cs.kieler.klay.layered.compaction.oned.CGraph CGraph}) by using a technique similar * to a longest path layering. * * The algorithm evaluates the {@link CGroup#reposition} flag. */ public class LongestPathCompaction implements ICompactionAlgorithm { /** * {@inheritDoc} */ @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; // ------------------------------------------ // #1 final positions for this group's nodes // ------------------------------------------ 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.cGroup.reposition //node.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; } // --------------------------------------------------- // #2 propagate start positions to constrained groups // --------------------------------------------------- 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); } } } } // ------------------------------------------------------ // #3 setting hitbox positions to new starting positions // ------------------------------------------------------ for (CNode cNode : compactor.cGraph.cNodes) { cNode.applyPosition(); } } }