use of org.eclipse.elk.graph.ElkNode in project elk by eclipse.
the class StraightLineEdgeRouter method routeEdges.
/**
* Route edges from node center to node center. Then clip it, to not cross the node.
*/
public void routeEdges(final ElkNode node) {
for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) {
if (!(edge.getSources().get(0) instanceof ElkPort)) {
ElkNode target = ElkGraphUtil.connectableShapeToNode(edge.getTargets().get(0));
if (!edge.isHierarchical()) {
double sourceX = node.getX() + node.getWidth() / 2;
double sourceY = node.getY() + node.getHeight() / 2;
double targetX = target.getX() + target.getWidth() / 2;
double targetY = target.getY() + target.getHeight() / 2;
// Clipping
KVector vector = new KVector();
vector.x = targetX - sourceX;
vector.y = targetY - sourceY;
KVector sourceClip = new KVector(vector.x, vector.y);
ElkMath.clipVector(sourceClip, node.getWidth(), node.getHeight());
vector.x -= sourceClip.x;
vector.y -= sourceClip.y;
sourceX = targetX - vector.x;
sourceY = targetY - vector.y;
KVector targetClip = new KVector(vector.x, vector.y);
ElkMath.clipVector(targetClip, target.getWidth(), target.getHeight());
vector.x -= targetClip.x;
vector.y -= targetClip.y;
targetX = sourceX + vector.x;
targetY = sourceY + vector.y;
ElkEdgeSection section = ElkGraphUtil.firstEdgeSection(edge, true, true);
section.setStartLocation(sourceX, sourceY);
section.setEndLocation(targetX, targetY);
routeEdges(target);
}
}
}
}
use of org.eclipse.elk.graph.ElkNode in project elk by eclipse.
the class PolarCoordinateSorter method setIDForNodes.
/**
* Iterates over the whole graph and assign an order id to each node, depending on its position in the list sorted
* by polar coordinates.
*
* @param nodes
* @param idOffset
* @return
*/
private int setIDForNodes(final List<ElkNode> nodes, final int idOffset) {
int id = idOffset;
int nextLayerId = 0;
for (ElkNode node : nodes) {
node.setProperty(RadialOptions.ORDER_ID, id++);
List<ElkNode> nodeSuccessors = RadialUtil.getSuccessors(node);
double arc = Math.atan2(node.getY() + node.getHeight() / 2, node.getX() + node.getWidth() / 2);
arc += arc < 0 ? 2 * Math.PI : 0;
// node is right of parent node
if (arc < DEGREE_45 || arc > DEGREE_315) {
nodeSuccessors.sort(compLeft);
} else if (arc <= DEGREE_315 && arc > DEGREE_225) {
// node is below parent node
nodeSuccessors.sort(compTop);
} else if (arc <= DEGREE_225 && arc > DEGREE_135) {
// node is left
nodeSuccessors.sort(compRight);
} else if (arc <= DEGREE_135) {
// node is top
nodeSuccessors.sort(compBottom);
}
nextLayerId = setIDForNodes(nodeSuccessors, nextLayerId);
}
return id;
}
use of org.eclipse.elk.graph.ElkNode in project elk by eclipse.
the class InteractiveRectPackingGraphVisitor method visit.
/* (non-Javadoc)
* @see org.eclipse.elk.core.util.IGraphElementVisitor#visit(org.eclipse.elk.graph.ElkGraphElement)
*/
@Override
public void visit(final ElkGraphElement element) {
// Only apply to root of the graph
if (element instanceof ElkNode) {
ElkNode root = (ElkNode) element;
setInteractiveOptions(root);
}
}
use of org.eclipse.elk.graph.ElkNode 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.graph.ElkNode in project elk by eclipse.
the class AreaApproximation method approxBoundingBox.
// ////////////////////////////////////////////////////////////////
// Public methods.
/**
* Calculates a drawing for the given rectangles according options set in the object creation of
* {@link AreaApproximation}. This method also sets the coordinates for the rectangles.
*
* @param rectangles The rectangles to place.
* @param nodeNodeSpacing The spacing between two nodes.
* @return A drawing calculated by this methods algorithm.
*/
public DrawingData approxBoundingBox(final List<ElkNode> rectangles, final double nodeNodeSpacing, final ElkPadding padding) {
// Place first box.
ElkNode firstRect = rectangles.get(0);
firstRect.setX(0);
firstRect.setY(0);
List<ElkNode> placedRects = new ArrayList<>();
placedRects.add(firstRect);
ElkNode lastPlaced = firstRect;
DrawingData currentValues = new DrawingData(this.aspectRatio, firstRect.getWidth(), firstRect.getHeight(), DrawingDataDescriptor.WHOLE_DRAWING);
// Place the other boxes.
for (int rectangleIdx = 1; rectangleIdx < rectangles.size(); rectangleIdx++) {
ElkNode toPlace = rectangles.get(rectangleIdx);
// Determine drawing metrics for different candidate positions/placement options
DrawingData opt1 = calcValuesForOpt(DrawingDataDescriptor.CANDIDATE_POSITION_LAST_PLACED_RIGHT, toPlace, lastPlaced, currentValues, placedRects, nodeNodeSpacing);
DrawingData opt2 = calcValuesForOpt(DrawingDataDescriptor.CANDIDATE_POSITION_LAST_PLACED_BELOW, toPlace, lastPlaced, currentValues, placedRects, nodeNodeSpacing);
DrawingData opt3 = calcValuesForOpt(DrawingDataDescriptor.CANDIDATE_POSITION_WHOLE_DRAWING_RIGHT, toPlace, lastPlaced, currentValues, placedRects, nodeNodeSpacing);
DrawingData opt4 = calcValuesForOpt(DrawingDataDescriptor.CANDIDATE_POSITION_WHOLE_DRAWING_BELOW, toPlace, lastPlaced, currentValues, placedRects, nodeNodeSpacing);
DrawingData bestOpt = findBestCandidate(opt1, opt2, opt3, opt4, toPlace, lastPlaced, padding);
toPlace.setX(bestOpt.getNextXcoordinate());
toPlace.setY(bestOpt.getNextYcoordinate());
bestOpt.setPlacementOption(DrawingDataDescriptor.WHOLE_DRAWING);
currentValues = bestOpt;
lastPlaced = toPlace;
placedRects.add(toPlace);
}
return currentValues;
}
Aggregations