use of org.eclipse.elk.core.math.KVectorChain in project elk by eclipse.
the class HierarchicalPortOrthogonalEdgeRouter method correctSlantedEdgeSegments.
/**
* Goes over the eastern and western hierarchical dummy nodes in the given layer and checks
* whether their incident edges have slanted segments. Note that only the first and last
* segment needs to be checked.
*
* @param layer the layer.
*/
private void correctSlantedEdgeSegments(final Layer layer) {
for (LNode node : layer) {
if (node.getType() != NodeType.EXTERNAL_PORT) {
// We're only looking for hierarchical port dummies
continue;
}
PortSide extPortSide = node.getProperty(InternalProperties.EXT_PORT_SIDE);
if (extPortSide == PortSide.EAST || extPortSide == PortSide.WEST) {
for (LEdge edge : node.getConnectedEdges()) {
KVectorChain bendPoints = edge.getBendPoints();
if (bendPoints.isEmpty()) {
// TODO: The edge has no bend points yet, but may still be slanted. Handle that!
continue;
}
// Correct a slanted segment connected to the source port if it belongs to our node
LPort sourcePort = edge.getSource();
if (sourcePort.getNode() == node) {
KVector firstBendPoint = bendPoints.getFirst();
firstBendPoint.y = sourcePort.getAbsoluteAnchor().y;
}
// Correct a slanted segment connected to the target port if it belongs to our node
LPort targetPort = edge.getTarget();
if (targetPort.getNode() == node) {
KVector lastBendPoint = bendPoints.getLast();
lastBendPoint.y = targetPort.getAbsoluteAnchor().y;
}
}
}
}
}
use of org.eclipse.elk.core.math.KVectorChain in project elk by eclipse.
the class HierarchicalPortOrthogonalEdgeRouter method removeTemporaryNorthSouthDummies.
// /////////////////////////////////////////////////////////////////////////////
// STEP 4: REMOVE TEMPORARY DUMMIES
/**
* Removes the temporary hierarchical port dummies, reconnecting their incoming and outgoing
* edges to the original dummies and setting the appropriate bend points.
*
* @param layeredGraph the layered graph.
*/
private void removeTemporaryNorthSouthDummies(final LGraph layeredGraph) {
List<LNode> nodesToRemove = Lists.newArrayList();
// Iterate through all layers
for (Layer layer : layeredGraph) {
for (LNode node : layer) {
if (node.getType() != NodeType.EXTERNAL_PORT) {
// We're only looking for hierarchical port dummies
continue;
}
if (!node.hasProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY)) {
// We're only looking for temporary north / south dummies
continue;
}
// There must be a port where all edges come in, another port where edges go out, and
// a port with an edge connecting node and origin (that one was added previously by
// this processor)
LPort nodeInPort = null;
LPort nodeOutPort = null;
LPort nodeOriginPort = null;
for (LPort port : node.getPorts()) {
switch(port.getSide()) {
case WEST:
nodeInPort = port;
break;
case EAST:
nodeOutPort = port;
break;
default:
nodeOriginPort = port;
}
}
// Find the edge connecting this dummy to the original external port dummy that we
// restored just a while ago
LEdge nodeToOriginEdge = nodeOriginPort.getOutgoingEdges().get(0);
// Compute bend points for incoming edges
KVectorChain incomingEdgeBendPoints = new KVectorChain(nodeToOriginEdge.getBendPoints());
KVector firstBendPoint = new KVector(nodeOriginPort.getPosition());
firstBendPoint.add(node.getPosition());
incomingEdgeBendPoints.add(0, firstBendPoint);
// Compute bend points for outgoing edges
KVectorChain outgoingEdgeBendPoints = KVectorChain.reverse(nodeToOriginEdge.getBendPoints());
KVector lastBendPoint = new KVector(nodeOriginPort.getPosition());
lastBendPoint.add(node.getPosition());
outgoingEdgeBendPoints.add(lastBendPoint);
// Retrieve the original hierarchical port dummy
LNode replacedDummy = (LNode) node.getProperty(InternalProperties.EXT_PORT_REPLACED_DUMMY);
LPort replacedDummyPort = replacedDummy.getPorts().get(0);
// Reroute all the input port's edges
LEdge[] edges = nodeInPort.getIncomingEdges().toArray(new LEdge[0]);
for (LEdge edge : edges) {
edge.setTarget(replacedDummyPort);
edge.getBendPoints().addAllAsCopies(edge.getBendPoints().size(), incomingEdgeBendPoints);
}
// Reroute all the output port's edges
edges = LGraphUtil.toEdgeArray(nodeOutPort.getOutgoingEdges());
for (LEdge edge : edges) {
edge.setSource(replacedDummyPort);
edge.getBendPoints().addAllAsCopies(0, outgoingEdgeBendPoints);
}
// Remove connection between node and original hierarchical port dummy
nodeToOriginEdge.setSource(null);
nodeToOriginEdge.setTarget(null);
// Remember the temporary node for removal
nodesToRemove.add(node);
}
}
// Remove nodes
for (LNode node : nodesToRemove) {
node.setLayer(null);
}
}
use of org.eclipse.elk.core.math.KVectorChain in project elk by eclipse.
the class GraphTransformer method mirrorX.
// /////////////////////////////////////////////////////////////////////////////
// Mirror Horizontally
/**
* Mirror the x coordinates of the given graph.
*
* @param nodes the nodes of the graph to transpose
* @param graph the graph the nodes are part of
*/
private void mirrorX(final List<LNode> nodes, final LGraph graph) {
/* Assuming that no nodes extend into negative x coordinates, mirroring a node means that the
* space left to its left border equals the space right to its right border when mirrored. In
* mathematical terms:
* oldPosition.x = graphWidth - newPosition.x - nodeWidth
* We use the offset variable to store graphWidth, since that's the constant offset against which
* we calculate the new node positions.
* This, however, stops to work once nodes are allowed to extend into negative coordinates. Then,
* we have to subtract from the graphWidth the amount of space the graph extends into negative
* coordinates. This amount is saved in the graph's graphOffset. Thus, our offset here becomes:
* offset = graphWidth - graphOffset.x
*/
double offset = 0;
// over its nodes
if (graph.getSize().x == 0) {
for (LNode node : nodes) {
offset = Math.max(offset, node.getPosition().x + node.getSize().x + node.getMargin().right);
}
} else {
offset = graph.getSize().x - graph.getOffset().x;
}
offset -= graph.getOffset().x;
// mirror all nodes, ports, edges, and labels
for (LNode node : nodes) {
mirrorX(node.getPosition(), offset - node.getSize().x);
mirrorX(node.getPadding());
mirrorNodeLabelPlacementX(node);
// mirror position
if (node.getAllProperties().containsKey(LayeredOptions.POSITION)) {
mirrorX(node.getProperty(LayeredOptions.POSITION), offset - node.getSize().x);
}
// mirror the alignment
switch(node.getProperty(LayeredOptions.ALIGNMENT)) {
case LEFT:
node.setProperty(LayeredOptions.ALIGNMENT, Alignment.RIGHT);
break;
case RIGHT:
node.setProperty(LayeredOptions.ALIGNMENT, Alignment.LEFT);
break;
}
KVector nodeSize = node.getSize();
for (LPort port : node.getPorts()) {
mirrorX(port.getPosition(), nodeSize.x - port.getSize().x);
mirrorX(port.getAnchor(), port.getSize().x);
mirrorPortSideX(port);
reverseIndex(port);
for (LEdge edge : port.getOutgoingEdges()) {
// Mirror bend points
for (KVector bendPoint : edge.getBendPoints()) {
mirrorX(bendPoint, offset);
}
// Mirror junction points
KVectorChain junctionPoints = edge.getProperty(LayeredOptions.JUNCTION_POINTS);
if (junctionPoints != null) {
for (KVector jp : junctionPoints) {
mirrorX(jp, offset);
}
}
// Mirror edge label positions
for (LLabel label : edge.getLabels()) {
mirrorX(label.getPosition(), offset - label.getSize().x);
}
}
// Mirror port label positions
for (LLabel label : port.getLabels()) {
mirrorX(label.getPosition(), port.getSize().x - label.getSize().x);
}
}
// External port dummy?
if (node.getType() == NodeType.EXTERNAL_PORT) {
mirrorExternalPortSideX(node);
mirrorLayerConstraintX(node);
}
// Mirror node labels
for (LLabel label : node.getLabels()) {
mirrorNodeLabelPlacementX(label);
mirrorX(label.getPosition(), nodeSize.x - label.getSize().x);
}
}
}
use of org.eclipse.elk.core.math.KVectorChain in project elk by eclipse.
the class GraphTransformer method mirrorY.
// /////////////////////////////////////////////////////////////////////////////
// Mirror Vertically
/**
* Mirror the y coordinates of the given graph.
*
* @param nodes the nodes of the graph to transpose
* @param graph the graph the nodes are part of
*/
private void mirrorY(final List<LNode> nodes, final LGraph graph) {
// See mirrorX for an explanation of how the offset is calculated
double offset = 0;
if (graph.getSize().y == 0) {
for (LNode node : nodes) {
offset = Math.max(offset, node.getPosition().y + node.getSize().y + node.getMargin().bottom);
}
} else {
offset = graph.getSize().y - graph.getOffset().y;
}
offset -= graph.getOffset().y;
// mirror all nodes, ports, edges, and labels
for (LNode node : nodes) {
mirrorY(node.getPosition(), offset - node.getSize().y);
mirrorY(node.getPadding());
mirrorNodeLabelPlacementY(node);
// mirror position
if (node.getAllProperties().containsKey(LayeredOptions.POSITION)) {
mirrorY(node.getProperty(LayeredOptions.POSITION), offset - node.getSize().y);
}
// mirror the alignment
switch(node.getProperty(LayeredOptions.ALIGNMENT)) {
case TOP:
node.setProperty(LayeredOptions.ALIGNMENT, Alignment.BOTTOM);
break;
case BOTTOM:
node.setProperty(LayeredOptions.ALIGNMENT, Alignment.TOP);
break;
}
KVector nodeSize = node.getSize();
for (LPort port : node.getPorts()) {
mirrorY(port.getPosition(), nodeSize.y - port.getSize().y);
mirrorY(port.getAnchor(), port.getSize().y);
mirrorPortSideY(port);
reverseIndex(port);
for (LEdge edge : port.getOutgoingEdges()) {
// Mirror bend points
for (KVector bendPoint : edge.getBendPoints()) {
mirrorY(bendPoint, offset);
}
// Mirror junction points
KVectorChain junctionPoints = edge.getProperty(LayeredOptions.JUNCTION_POINTS);
if (junctionPoints != null) {
for (KVector jp : junctionPoints) {
mirrorY(jp, offset);
}
}
// Mirror edge label positions
for (LLabel label : edge.getLabels()) {
mirrorY(label.getPosition(), offset - label.getSize().y);
}
}
// Mirror port label positions
for (LLabel label : port.getLabels()) {
mirrorY(label.getPosition(), port.getSize().y - label.getSize().y);
}
}
// External port dummy?
if (node.getType() == NodeType.EXTERNAL_PORT) {
mirrorExternalPortSideY(node);
mirrorInLayerConstraintY(node);
}
// Mirror node labels
for (LLabel label : node.getLabels()) {
mirrorNodeLabelPlacementY(label);
mirrorY(label.getPosition(), nodeSize.y - label.getSize().y);
}
}
}
use of org.eclipse.elk.core.math.KVectorChain in project elk by eclipse.
the class GraphRenderer method renderEdge.
/**
* Paints an edge for the given dirty area.
*
* @param edge the edge to paint
* @param graphics the graphics context used to paint
* @param area dirty area that needs painting
* @param offset offset to be added to relative coordinates
* @param labelAlpha alpha value for labels
*/
private void renderEdge(final ElkEdge edge, final GC graphics, final Rectangle area, final KVector offset, final int labelAlpha) {
if (configurator.getEdgeColor() == null) {
return;
}
// Find our if the edge is actually eligible to be painted
if (isEdgeFullyContainedInGraphToDraw(edge)) {
// Get a PaintRectangle ready for the edge
PaintRectangle rect = boundsMap.get(edge);
if (rect == null) {
rect = new PaintRectangle(edge, offset, scale);
boundsMap.put(edge, rect);
}
if (!rect.painted && rect.intersects(area)) {
// Gather some information
final boolean splineEdge = edge.getProperty(CoreOptions.EDGE_ROUTING) == EdgeRouting.SPLINES;
final boolean directedEdge = edge.getProperty(CoreOptions.EDGE_TYPE) != EdgeType.UNDIRECTED;
graphics.setAlpha(255);
// The background color is required to fill the arrow of directed edges
graphics.setForeground(configurator.getEdgeColor());
graphics.setBackground(configurator.getEdgeColor());
for (ElkEdgeSection edgeSection : edge.getSections()) {
KVectorChain bendPoints = ElkUtil.createVectorChain(edgeSection);
bendPoints.scale(scale).offset(offset);
// Draw the damn edge already...!
Path path = new Path(graphics.getDevice());
Iterator<KVector> pointIter = bendPoints.iterator();
KVector startPoint = pointIter.next();
path.moveTo((float) startPoint.x, (float) startPoint.y);
KVector point1 = null;
KVector point2 = null;
while (pointIter.hasNext()) {
if (splineEdge) {
if (point1 == null) {
point1 = pointIter.next();
} else if (point2 == null) {
point2 = pointIter.next();
} else {
KVector endPoint = pointIter.next();
path.cubicTo((float) point1.x, (float) point1.y, (float) point2.x, (float) point2.y, (float) endPoint.x, (float) endPoint.y);
point1 = null;
point2 = null;
}
} else {
KVector nextPoint = pointIter.next();
path.lineTo((float) nextPoint.x, (float) nextPoint.y);
}
}
if (splineEdge && point2 != null) {
path.quadTo((float) point1.x, (float) point1.y, (float) point2.x, (float) point2.y);
} else if (splineEdge && point1 != null) {
path.lineTo((float) point1.x, (float) point1.y);
}
graphics.drawPath(path);
if (directedEdge) {
// Draw an arrow at the last segment of the connection
KVector referencePoint;
if (splineEdge && (bendPoints.size() - 1) % 3 != 1) {
int beginIndex;
if ((bendPoints.size() - 1) % 3 == 2) {
beginIndex = bendPoints.size() - 2;
} else {
beginIndex = bendPoints.size() - 3;
}
referencePoint = ElkMath.getPointOnBezierSegment(0.5, bendPoints.toArray(beginIndex));
} else {
referencePoint = bendPoints.get(bendPoints.size() - 2);
}
int[] arrowPoly = makeArrow(referencePoint, bendPoints.getLast());
if (arrowPoly != null) {
graphics.fillPolygon(arrowPoly);
}
}
}
rect.painted = true;
}
}
// paint junction points
KVectorChain vc = edge.getProperty(CoreOptions.JUNCTION_POINTS);
if (vc != null) {
for (KVector v : vc) {
KVector center = v.clone().scale(scale).add(offset).sub(2, 2);
graphics.fillOval((int) center.x, (int) center.y, 6, 6);
}
}
// paint the edge labels
if (configurator.getEdgeLabelFont() != null) {
graphics.setFont(configurator.getEdgeLabelFont());
for (ElkLabel label : edge.getLabels()) {
renderLabel(label, graphics, area, offset, labelAlpha);
}
}
}
Aggregations