use of org.eclipse.elk.core.math.ElkPadding in project elk by eclipse.
the class RectPackingLayoutProvider method layout.
/**
* Calculating and applying layout to the model.
*/
@Override
public void layout(final ElkNode layoutGraph, final IElkProgressMonitor progressMonitor) {
progressMonitor.begin("Rectangle Packing", 1);
if (progressMonitor.isLoggingEnabled()) {
progressMonitor.logGraph(layoutGraph, "Input");
}
// The desired aspect ratio.
double aspectRatio = layoutGraph.getProperty(RectPackingOptions.ASPECT_RATIO);
// The strategy for the initial width approximation.
OptimizationGoal goal = layoutGraph.getProperty(RectPackingOptions.OPTIMIZATION_GOAL);
// Option for better width approximation.
boolean lastPlaceShift = layoutGraph.getProperty(RectPackingOptions.LAST_PLACE_SHIFT);
// Option to only do the initial width approximation.
boolean onlyFirstIteration = layoutGraph.getProperty(RectPackingOptions.ONLY_FIRST_ITERATION);
// Option whether the nodes should be expanded to fill the bounding rectangle.
boolean expandNodes = layoutGraph.getProperty(RectPackingOptions.EXPAND_NODES);
// The padding surrounding the drawing.
ElkPadding padding = layoutGraph.getProperty(RectPackingOptions.PADDING);
// The spacing between two nodes.
double nodeNodeSpacing = layoutGraph.getProperty(RectPackingOptions.SPACING_NODE_NODE);
// Whether the nodes are compacted after the initial placement.
boolean compaction = layoutGraph.getProperty(RectPackingOptions.ROW_COMPACTION);
// Whether the nodes should be expanded to fit the aspect ratio during node expansion.
// Only effective if nodes are expanded.
boolean expandToAspectRatio = layoutGraph.getProperty(RectPackingOptions.EXPAND_TO_ASPECT_RATIO);
// Whether interactive layout is activ.
boolean interactive = layoutGraph.getProperty(RectPackingOptions.INTERACTIVE);
// A target width for the algorithm. If this is set the width approximation step is skipped.
double targetWidth = layoutGraph.getProperty(RectPackingOptions.TARGET_WIDTH);
List<ElkNode> rectangles = layoutGraph.getChildren();
DrawingUtil.resetCoordinates(rectangles);
DrawingData drawing;
if (interactive) {
List<ElkNode> fixedNodes = new ArrayList<>();
for (ElkNode elkNode : rectangles) {
if (elkNode.hasProperty(RectPackingOptions.DESIRED_POSITION)) {
fixedNodes.add(elkNode);
}
}
for (ElkNode elkNode : fixedNodes) {
rectangles.remove(elkNode);
}
Collections.sort(fixedNodes, (a, b) -> {
int positionA = a.getProperty(RectPackingOptions.DESIRED_POSITION);
int positionB = b.getProperty(RectPackingOptions.DESIRED_POSITION);
if (positionA == positionB) {
return -1;
} else {
return Integer.compare(positionA, positionB);
}
});
for (ElkNode elkNode : fixedNodes) {
int position = elkNode.getProperty(RectPackingOptions.DESIRED_POSITION);
position = Math.min(position, rectangles.size());
rectangles.add(position, elkNode);
}
int index = 0;
for (ElkNode elkNode : rectangles) {
elkNode.setProperty(RectPackingOptions.CURRENT_POSITION, index);
index++;
}
}
// Get minimum size of parent.
KVector minSize = ElkUtil.effectiveMinSizeConstraintFor(layoutGraph);
// Remove padding to get the space the algorithm can use.
minSize.x -= padding.getHorizontal();
minSize.y -= padding.getVertical();
double maxWidth = minSize.x;
if (targetWidth < 0 || targetWidth < minSize.x) {
// Initial width approximation.
AreaApproximation firstIt = new AreaApproximation(aspectRatio, goal, lastPlaceShift);
drawing = firstIt.approxBoundingBox(rectangles, nodeNodeSpacing, padding);
if (progressMonitor.isLoggingEnabled()) {
progressMonitor.logGraph(layoutGraph, "After approximation");
}
} else {
drawing = new DrawingData(aspectRatio, targetWidth, 0, DrawingDataDescriptor.WHOLE_DRAWING);
}
// Readd padding for next steps.
minSize.x += padding.getHorizontal();
minSize.y += padding.getVertical();
// Placement according to approximated width.
if (!onlyFirstIteration) {
DrawingUtil.resetCoordinates(rectangles);
RowFillingAndCompaction secondIt = new RowFillingAndCompaction(aspectRatio, expandNodes, expandToAspectRatio, compaction, nodeNodeSpacing);
// Modify the initial approximation if necessary.
maxWidth = Math.max(minSize.x, drawing.getDrawingWidth());
// Run placement, compaction, and expansion (if enabled).
drawing = secondIt.start(rectangles, maxWidth, minSize, progressMonitor, layoutGraph);
}
// Final touch.
applyPadding(rectangles, padding);
ElkUtil.resizeNode(layoutGraph, drawing.getDrawingWidth() + padding.getHorizontal(), drawing.getDrawingHeight() + padding.getVertical(), false, true);
// if requested, compute nodes's dimensions, place node labels, ports, port labels, etc.
if (!layoutGraph.getProperty(RectPackingOptions.OMIT_NODE_MICRO_LAYOUT)) {
NodeMicroLayout.forGraph(layoutGraph).execute();
}
if (progressMonitor.isLoggingEnabled()) {
progressMonitor.logGraph(layoutGraph, "Output");
}
progressMonitor.done();
}
use of org.eclipse.elk.core.math.ElkPadding in project elk by eclipse.
the class CalculateGraphSize method process.
/**
* Shift the nodes such that each nodes has x and y coordinates bigger 0.
*/
public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) {
progressMonitor.begin("Calculate Graph Size", 1);
progressMonitor.logGraph(graph, "Before");
// calculate the offset from border spacing and node distribution
double minXPos = Double.MAX_VALUE;
double minYPos = Double.MAX_VALUE;
double maxXPos = Double.MIN_VALUE;
double maxYPos = Double.MIN_VALUE;
for (ElkNode node : graph.getChildren()) {
double posX = node.getX();
double posY = node.getY();
double width = node.getWidth();
double height = node.getHeight();
ElkMargin margins = node.getProperty(CoreOptions.MARGINS);
minXPos = Math.min(minXPos, posX - margins.left);
minYPos = Math.min(minYPos, posY - margins.top);
maxXPos = Math.max(maxXPos, posX + width + margins.right);
maxYPos = Math.max(maxYPos, posY + height + margins.bottom);
}
ElkPadding padding = graph.getProperty(CoreOptions.PADDING);
KVector offset = new KVector(minXPos - padding.getLeft(), minYPos - padding.getTop());
// process the nodes
for (ElkNode node : graph.getChildren()) {
// set the node position
node.setX(node.getX() - offset.x);
node.setY(node.getY() - offset.y);
}
// set up the graph
double width = maxXPos - minXPos + padding.getHorizontal();
double height = maxYPos - minYPos + padding.getVertical();
graph.setWidth(width);
graph.setHeight(height);
progressMonitor.logGraph(graph, "After");
}
use of org.eclipse.elk.core.math.ElkPadding in project elk by eclipse.
the class BoxLayoutProvider method layout.
@Override
public void layout(final ElkNode layoutNode, final IElkProgressMonitor progressMonitor) {
progressMonitor.begin("Box layout", 2);
float objSpacing = layoutNode.getProperty(BoxLayouterOptions.SPACING_NODE_NODE).floatValue();
ElkPadding padding = layoutNode.getProperty(BoxLayouterOptions.PADDING);
boolean expandNodes = layoutNode.getProperty(BoxLayouterOptions.EXPAND_NODES);
boolean interactive = layoutNode.getProperty(BoxLayouterOptions.INTERACTIVE);
switch(layoutNode.getProperty(BoxLayouterOptions.BOX_PACKING_MODE)) {
case SIMPLE:
placeBoxes(layoutNode, objSpacing, padding, expandNodes, interactive);
break;
default:
// any of the groups
placeBoxesGrouping(layoutNode, objSpacing, padding, expandNodes);
}
progressMonitor.done();
}
use of org.eclipse.elk.core.math.ElkPadding in project elk by eclipse.
the class DotExporter method transformNodes.
/**
* Transform the child nodes of the given parent node.
*
* @param parent a parent node
* @param statements the list to which new statements are added
* @param offset offset of the parent node in the whole graph
* @param transData transformation data
*/
private void transformNodes(final ElkNode parent, final List<Statement> statements, final KVector offset, final IDotTransformationData<ElkNode, GraphvizModel> transData) {
// set attributes for the whole graph
setGraphAttributes(statements, parent, transData);
// create nodes and subgraphs
boolean hierarchy = transData.getProperty(HIERARCHY);
boolean transformNodeLayout = transData.getProperty(TRANSFORM_NODE_LAYOUT);
boolean transformNodeLabels = transData.getProperty(TRANSFORM_NODE_LABELS);
for (ElkNode childNode : parent.getChildren()) {
NodeStatement nodeStatement = DotFactory.eINSTANCE.createNodeStatement();
List<Attribute> attributes = nodeStatement.getAttributes();
String nodeID;
// if hierarchy mode is active, create a subgraph, else a regular node
if (hierarchy && !childNode.getChildren().isEmpty()) {
String clusterNodeID = getNodeID(childNode, NodeType.CLUSTER, transData);
Subgraph subgraph = DotFactory.eINSTANCE.createSubgraph();
subgraph.setName(clusterNodeID);
statements.add(subgraph);
// transform child nodes recursively
ElkPadding padding = childNode.getProperty(CoreOptions.PADDING);
double subgraphx = childNode.getX() + padding.getLeft();
double subgraphy = childNode.getY() + padding.getTop();
transformNodes(childNode, subgraph.getStatements(), new KVector(offset).add(subgraphx, subgraphy), transData);
// create a dummy node for compound edges
nodeID = getNodeID(childNode, NodeType.DUMMY, transData);
attributes.add(createAttribute(Attributes.STYLE, "invis"));
attributes.add(createAttribute(Attributes.WIDTH, 0));
attributes.add(createAttribute(Attributes.HEIGHT, 0));
subgraph.getStatements().add(nodeStatement);
} else {
nodeID = getNodeID(childNode, NodeType.NODE, transData);
// set width and height
ElkUtil.resizeNode(childNode);
if (childNode.getWidth() > 0) {
attributes.add(createAttribute(Attributes.WIDTH, childNode.getWidth() / DPI));
}
if (childNode.getHeight() > 0) {
attributes.add(createAttribute(Attributes.HEIGHT, childNode.getHeight() / DPI));
}
if (transformNodeLabels && !childNode.getLabels().isEmpty() && childNode.getLabels().get(0).getText().length() > 0) {
attributes.add(createAttribute(Attributes.LABEL, createString(childNode.getLabels().get(0).getText())));
}
// add node position if interactive layout is chosen
if (transformNodeLayout && (childNode.getX() != 0 || childNode.getY() != 0)) {
double xpos = (childNode.getX() + childNode.getWidth() / 2 + offset.x);
double ypos = (childNode.getY() + childNode.getHeight() / 2 + offset.y);
String posString = "\"" + Double.toString(xpos) + "," + Double.toString(ypos) + "\"";
attributes.add(createAttribute(Attributes.POS, posString));
}
statements.add(nodeStatement);
}
Node node = DotFactory.eINSTANCE.createNode();
node.setName(nodeID);
nodeStatement.setNode(node);
}
}
use of org.eclipse.elk.core.math.ElkPadding in project elk by eclipse.
the class DotExporter method transferLayout.
/**
* Applies the layout information attached to the given Dot instance to the KGraph instance
* using the mapping created by a previous call to {@code transform}. Has to be called after a
* call to {@code transform}.
*
* @param transData the transformation data instance
*/
public void transferLayout(final IDotTransformationData<ElkNode, GraphvizModel> transData) {
ElkPadding padding = transData.getSourceGraph().getProperty(CoreOptions.PADDING);
Graph graph = transData.getTargetGraphs().get(0).getGraphs().get(0);
// process nodes and subgraphs
KVector baseOffset = new KVector();
applyLayout(transData.getSourceGraph(), graph.getStatements(), baseOffset, padding, transData);
// finally process the edges
LinkedList<Statement> statements = new LinkedList<Statement>(graph.getStatements());
KVector edgeOffset = baseOffset.add(padding.getLeft(), padding.getTop());
while (!statements.isEmpty()) {
Statement statement = statements.removeFirst();
if (statement instanceof EdgeStatement) {
applyEdgeLayout((EdgeStatement) statement, edgeOffset, transData);
} else if (statement instanceof Subgraph) {
statements.addAll(((Subgraph) statement).getStatements());
}
}
}
Aggregations