use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class SouthToNorthRoutingStrategy method calculateBendPoints.
@Override
public void calculateBendPoints(final HyperEdgeSegment segment, final double startPos, final double edgeSpacing) {
// We don't do anything with dummy segments; they are dealt with when their partner is processed
if (segment.isDummy()) {
return;
}
// Calculate coordinates for each port's bend points
double segmentY = startPos - segment.getRoutingSlot() * edgeSpacing;
for (LPort port : segment.getPorts()) {
double sourceX = port.getAbsoluteAnchor().x;
for (LEdge edge : port.getOutgoingEdges()) {
if (!edge.isSelfLoop()) {
LPort target = edge.getTarget();
double targetX = target.getAbsoluteAnchor().x;
if (Math.abs(sourceX - targetX) > OrthogonalRoutingGenerator.TOLERANCE) {
// We'll update these if we find that the segment was split
double currentY = segmentY;
HyperEdgeSegment currentSegment = segment;
KVector bend = new KVector(sourceX, currentY);
edge.getBendPoints().add(bend);
addJunctionPointIfNecessary(edge, currentSegment, bend, false);
// If this segment was split, we need two additional bend points
HyperEdgeSegment splitPartner = segment.getSplitPartner();
if (splitPartner != null) {
double splitX = splitPartner.getIncomingConnectionCoordinates().get(0);
bend = new KVector(splitX, currentY);
edge.getBendPoints().add(bend);
addJunctionPointIfNecessary(edge, currentSegment, bend, false);
// Advance to the split partner's routing slot
currentY = startPos - splitPartner.getRoutingSlot() * edgeSpacing;
currentSegment = splitPartner;
bend = new KVector(splitX, currentY);
edge.getBendPoints().add(bend);
addJunctionPointIfNecessary(edge, currentSegment, bend, false);
}
bend = new KVector(targetX, currentY);
edge.getBendPoints().add(bend);
addJunctionPointIfNecessary(edge, currentSegment, bend, false);
}
}
}
}
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class PolylineEdgeRouter method processNode.
// //////////////////////////////////////////////////////////////////////////////////////////////////
// Actual Edge Routing Code
/**
* Inserts bend points for edges incident to this node. The bend points are inserted such that
* the segments that cross the layer's area are straight or pretty much straight. A bend point
* is only added if it's necessary: if the bend point to be inserted differs from the edge's end
* point.
*
* @param node
* the node whose incident edges to insert bend points for.
* @param layerLeftXPos
* the x position of the node's layer.
* @param maxAcceptableXDiff
* the maximum space between node and layer boundary before bend points need to be inserted.
*/
private void processNode(final LNode node, final double layerLeftXPos, final double maxAcceptableXDiff) {
// The right side of the layer
final double layerRightXPos = layerLeftXPos + node.getLayer().getSize().x;
for (LPort port : node.getPorts()) {
KVector absolutePortAnchor = port.getAbsoluteAnchor();
if (node.getType() == NodeType.NORTH_SOUTH_PORT) {
// North/south ports require special handling (also see #515):
// The dummy node that represents the north/south port will have been placed at:
// - the very left x-coordinate of the currently processed layer for incoming edges
// - the very right x-coordinate for outgoing edges
// However, the actual x-coordinate of the port itself is very likely to have a different x-coordinate.
// The code below introduces bendpoints that prevent edge/node overlaps based on a condition that
// checks that a node's position is "far enough away" from the left-most x-coordinate of the layer.
// Consequently, we have to use the north/south port's x-coordinate instead of the dummy node's one.
LPort correspondingPort = (LPort) port.getProperty(InternalProperties.ORIGIN);
absolutePortAnchor.x = correspondingPort.getAbsoluteAnchor().x;
// While it makes sense either way, it is important to move the dummy node to the correct location
// as well. Otherwise the #addBendPoint(...) method won't add the computed bendpoint as it
// thinks it's superfluous.
node.getPosition().x = absolutePortAnchor.x;
}
KVector bendPoint = new KVector(0, absolutePortAnchor.y);
if (port.getSide() == PortSide.EAST) {
bendPoint.x = layerRightXPos;
} else if (port.getSide() == PortSide.WEST) {
bendPoint.x = layerLeftXPos;
} else {
// We only know what to do with eastern and western ports
continue;
}
// If the port's absolute anchor equals the bend point, we don't want to insert anything
// (unless the node represents an in-layer dummy)
double xDistance = Math.abs(absolutePortAnchor.x - bendPoint.x);
if (xDistance <= maxAcceptableXDiff && !isInLayerDummy(node)) {
continue;
}
// Whether to add a junction point or not
boolean addJunctionPoint = port.getOutgoingEdges().size() + port.getIncomingEdges().size() > 1;
// Iterate over the edges and add bend (and possibly junction) points
for (LEdge e : port.getConnectedEdges()) {
LPort otherPort = e.getSource() == port ? e.getTarget() : e.getSource();
if (Math.abs(otherPort.getAbsoluteAnchor().y - bendPoint.y) > MIN_VERT_DIFF) {
// Insert bend point
addBendPoint(e, bendPoint, addJunctionPoint, port);
}
}
}
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class PolylineEdgeRouter method addBendPoint.
/**
* Adds a copy of the given bend point to the given edge at the appropriate place in the list of
* bend points. The appropriate place is determined by the given port: if it's the source port,
* the bend point is prepended to the list; otherwise is is appended. The bend point is not
* added to the list at all if it wouldn't have any visual effect; that is, if the port's anchor
* equals the bend point.
*
* @param edge
* the edge to add the bend point to.
* @param bendPoint
* the bend point to add.
* @param addJunctionPoint
* if {@code true}, a copy of the bend point will be added to the edge's list of
* junction points, if necessary.
* @param currPort
* the port the bend point is near.
*/
private void addBendPoint(final LEdge edge, final KVector bendPoint, final boolean addJunctionPoint, final LPort currPort) {
// any case
if ((edge.isInLayerEdge() || !currPort.getAbsoluteAnchor().equals(bendPoint)) && !edge.isSelfLoop()) {
if (edge.getSource() == currPort) {
edge.getBendPoints().add(0, new KVector(bendPoint));
} else {
edge.getBendPoints().add(new KVector(bendPoint));
}
if (addJunctionPoint && !createdJunctionPoints.contains(bendPoint)) {
// create a new junction point for the edge at the bend point's position
KVectorChain junctionPoints = edge.getProperty(LayeredOptions.JUNCTION_POINTS);
if (junctionPoints == null) {
junctionPoints = new KVectorChain();
edge.setProperty(LayeredOptions.JUNCTION_POINTS, junctionPoints);
}
KVector jpoint = new KVector(bendPoint);
junctionPoints.add(jpoint);
createdJunctionPoints.add(jpoint);
}
}
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class NodePositionProcessor method setCoordinates.
/**
* Set the coordinate for each node in a given level and all underlying levels.
*
* @param currentLevel
* the list of TNode for which the neighbors should be calculated
* @param level
* the level index
* @param progressMonitor
* the current progress monitor
*/
private void setCoordinates(final LinkedList<TNode> currentLevel, final IElkProgressMonitor progressMonitor) {
/**
* if the level is empty there is nothing to do
*/
if (!currentLevel.isEmpty()) {
LinkedList<TNode> nextLevel = new LinkedList<TNode>();
/**
* set the coordinates for each node in the current level and collect the nodes of the
* next level
*/
for (TNode tNode : currentLevel) {
nextLevel.addAll(tNode.getChildrenCopy());
KVector pos = tNode.getPosition();
pos.x = tNode.getProperty(InternalProperties.XCOOR).doubleValue();
pos.y = tNode.getProperty(InternalProperties.YCOOR).doubleValue();
}
/**
* go to the next level
*/
setCoordinates(nextLevel, progressMonitor.subTask(nextLevel.size() / numberOfNodes));
}
}
use of org.eclipse.elk.core.math.KVector in project elk by eclipse.
the class SimpleNodePlacer method process.
@Override
public void process(final LGraph layeredGraph, final IElkProgressMonitor monitor) {
monitor.begin("Simple node placement", 1);
Spacings spacings = layeredGraph.getProperty(InternalProperties.SPACINGS);
// first iteration: determine the height of each layer
double maxHeight = 0;
for (Layer layer : layeredGraph.getLayers()) {
KVector layerSize = layer.getSize();
layerSize.y = 0;
LNode lastNode = null;
for (LNode node : layer.getNodes()) {
if (lastNode != null) {
// use normal spacing as soon as a regular node is involved
layerSize.y += spacings.getVerticalSpacing(node, lastNode);
}
layerSize.y += node.getMargin().top + node.getSize().y + node.getMargin().bottom;
lastNode = node;
}
maxHeight = Math.max(maxHeight, layerSize.y);
}
// second iteration: center the nodes of each layer around the tallest layer
for (Layer layer : layeredGraph.getLayers()) {
KVector layerSize = layer.getSize();
double pos = (maxHeight - layerSize.y) / 2;
LNode lastNode = null;
for (LNode node : layer.getNodes()) {
if (lastNode != null) {
pos += spacings.getVerticalSpacing(node, lastNode);
}
pos += node.getMargin().top;
node.getPosition().y = pos;
pos += node.getSize().y + node.getMargin().bottom;
lastNode = node;
}
}
monitor.done();
}
Aggregations