Search in sources :

Example 41 with KVector

use of org.eclipse.elk.core.math.KVector 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);
        }
    }
}
Also used : Path(org.eclipse.swt.graphics.Path) ElkLabel(org.eclipse.elk.graph.ElkLabel) KVectorChain(org.eclipse.elk.core.math.KVectorChain) KVector(org.eclipse.elk.core.math.KVector) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint)

Example 42 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class GraphRenderingCanvas method setLayoutGraph.

/**
 * Sets the given layout graph as the painted graph.
 *
 * @param graph layout graph to be painted
 */
public void setLayoutGraph(final ElkNode graph) {
    KVector baseOffset = calculateRequiredCanvasSizeAndBaseOffset(graph);
    this.layoutGraph = graph;
    graphRenderer.setBaseOffset(baseOffset);
    redraw();
}
Also used : KVector(org.eclipse.elk.core.math.KVector)

Example 43 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class GraphRenderingCanvas method pan.

/**
 * Pan the canvas by adjusting the base offset by the given delta.
 */
protected void pan(final KVector delta) {
    KVector offset = graphRenderer.getBaseOffset().add(delta);
    // Though the offset is modified in place, it needs to be reset in order to flush the cache
    graphRenderer.setBaseOffset(offset);
}
Also used : KVector(org.eclipse.elk.core.math.KVector)

Example 44 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class GraphRenderingCanvas method calculateRequiredCanvasSizeAndBaseOffset.

/**
 * Sets size of the canvas by looking up the biggest distances between graph elements in x- and y-direction
 * and return a KVector with the required offset of the origin coordinates to fit all elements on the canvas.
 *
 * @param graph to be painted
 */
private KVector calculateRequiredCanvasSizeAndBaseOffset(final ElkNode graph) {
    if (graph != null) {
        double minX = Double.MAX_VALUE;
        double maxX = Double.MIN_VALUE;
        double minY = Double.MAX_VALUE;
        double maxY = Double.MIN_VALUE;
        // check all nodes for their coordinates
        for (ElkNode node : graph.getChildren()) {
            minX = Math.min(minX, node.getX());
            maxX = Math.max(maxX, node.getX() + node.getWidth());
            minY = Math.min(minY, node.getY());
            maxY = Math.max(maxY, node.getY() + node.getHeight());
            // check node labels
            for (ElkLabel nodeLabel : node.getLabels()) {
                minX = Math.min(minX, node.getX() + nodeLabel.getX());
                maxX = Math.max(maxX, node.getX() + nodeLabel.getX() + nodeLabel.getWidth());
                minY = Math.min(minY, node.getY() + nodeLabel.getY());
                maxY = Math.max(maxY, node.getY() + nodeLabel.getY() + nodeLabel.getHeight());
            }
        }
        for (ElkEdge edge : graph.getContainedEdges()) {
            // check all sections of the edges for their coordinates
            for (ElkEdgeSection edgeSection : edge.getSections()) {
                minX = Math.min(minX, edgeSection.getStartX());
                minY = Math.min(minY, edgeSection.getStartY());
                maxX = Math.max(maxX, edgeSection.getStartX());
                maxY = Math.max(maxY, edgeSection.getStartY());
                minX = Math.min(minX, edgeSection.getEndX());
                minY = Math.min(minY, edgeSection.getEndY());
                maxX = Math.max(maxX, edgeSection.getEndX());
                maxY = Math.max(maxY, edgeSection.getEndY());
                for (ElkBendPoint bendPoint : edgeSection.getBendPoints()) {
                    minX = Math.min(minX, bendPoint.getX());
                    minY = Math.min(minY, bendPoint.getY());
                    maxX = Math.max(maxX, bendPoint.getX());
                    maxY = Math.max(maxY, bendPoint.getY());
                }
            }
            // check edge labels
            for (ElkLabel edgeLabel : edge.getLabels()) {
                minX = Math.min(minX, edgeLabel.getX());
                maxX = Math.max(maxX, edgeLabel.getX() + edgeLabel.getWidth());
                minY = Math.min(minY, edgeLabel.getY());
                maxY = Math.max(maxY, edgeLabel.getY() + edgeLabel.getHeight());
            }
        }
        int x = ((int) (Math.max(graph.getWidth(), maxX) - Math.min(0, minX))) + 1;
        int y = ((int) (Math.max(graph.getHeight(), maxY) - Math.min(0, minY))) + 1;
        setSize(new Point(x, y));
        return new KVector((-Math.min(0, minX)), (-Math.min(0, minY)));
    }
    return new KVector();
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) ElkLabel(org.eclipse.elk.graph.ElkLabel) ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint) Point(org.eclipse.swt.graphics.Point) ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint) KVector(org.eclipse.elk.core.math.KVector) ElkEdgeSection(org.eclipse.elk.graph.ElkEdgeSection) Point(org.eclipse.swt.graphics.Point) ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 45 with KVector

use of org.eclipse.elk.core.math.KVector in project elk by eclipse.

the class BoxLayoutProvider method placeBoxes.

/**
 * Place the boxes of the given sorted list according to their order in the list.
 *
 * @param sortedBoxes sorted list of boxes
 * @param minSpacing minimal spacing between elements
 * @param borderSpacing spacing to the border
 * @param minTotalWidth minimal width of the parent node
 * @param minTotalHeight minimal height of the parent node
 * @param expandNodes if true, the nodes are expanded to fill their parent
 * @param aspectRatio the desired aspect ratio
 * @return the bounding box of the resulting layout
 */
private KVector placeBoxes(final List<ElkNode> sortedBoxes, final double minSpacing, final ElkPadding padding, final double minTotalWidth, final double minTotalHeight, final boolean expandNodes, final double aspectRatio) {
    // determine the maximal row width by the maximal box width and the total area
    double maxRowWidth = 0.0f;
    double totalArea = 0.0f;
    for (ElkNode box : sortedBoxes) {
        ElkUtil.resizeNode(box);
        maxRowWidth = Math.max(maxRowWidth, box.getWidth());
        totalArea += box.getWidth() * box.getHeight();
    }
    // calculate std deviation
    // rationale: the greater the diversity of box sizes, the more space will be 'wasted',
    // contributing to the total area. We address this by adding x*n*stddev to the area.
    // TODO x should be assessed empirically, for the moment set it to 1
    double mean = totalArea / sortedBoxes.size();
    double stddev = areaStdDev(sortedBoxes, mean);
    totalArea += (sortedBoxes.size() * 1 * stddev);
    // calculate the required row width w to achieve the desired aspect ratio,
    // i.e.:  w*h=area s.t. w/h=dar  ->  w=sqrt(area * dar)
    maxRowWidth = Math.max(maxRowWidth, Math.sqrt(totalArea * aspectRatio)) + padding.getLeft();
    // place nodes iteratively into rows
    double xpos = padding.getLeft();
    double ypos = padding.getTop();
    double highestBox = 0.0f;
    double broadestRow = padding.getHorizontal();
    LinkedList<Integer> rowIndices = new LinkedList<>();
    rowIndices.add(Integer.valueOf(0));
    LinkedList<Double> rowHeights = new LinkedList<>();
    ListIterator<ElkNode> boxIter = sortedBoxes.listIterator();
    while (boxIter.hasNext()) {
        ElkNode box = boxIter.next();
        double width = box.getWidth();
        double height = box.getHeight();
        if (xpos + width > maxRowWidth) {
            // place box into the next row
            if (expandNodes) {
                rowHeights.addLast(Double.valueOf(highestBox));
                rowIndices.addLast(Integer.valueOf(boxIter.previousIndex()));
            }
            xpos = padding.getLeft();
            ypos += highestBox + minSpacing;
            highestBox = 0.0f;
            broadestRow = Math.max(broadestRow, padding.getHorizontal() + width);
        }
        box.setLocation(xpos, ypos);
        broadestRow = Math.max(broadestRow, xpos + width + padding.getRight());
        highestBox = Math.max(highestBox, height);
        xpos += width + minSpacing;
    }
    broadestRow = Math.max(broadestRow, minTotalWidth);
    double totalHeight = ypos + highestBox + padding.getBottom();
    if (totalHeight < minTotalHeight) {
        highestBox += minTotalHeight - totalHeight;
        totalHeight = minTotalHeight;
    }
    // expand nodes if required
    if (expandNodes) {
        xpos = padding.getLeft();
        boxIter = sortedBoxes.listIterator();
        rowIndices.addLast(Integer.valueOf(sortedBoxes.size()));
        ListIterator<Integer> rowIndexIter = rowIndices.listIterator();
        int nextRowIndex = rowIndexIter.next();
        rowHeights.addLast(Double.valueOf(highestBox));
        ListIterator<Double> rowHeightIter = rowHeights.listIterator();
        double rowHeight = 0.0f;
        while (boxIter.hasNext()) {
            if (boxIter.nextIndex() == nextRowIndex) {
                xpos = padding.getLeft();
                rowHeight = rowHeightIter.next();
                nextRowIndex = rowIndexIter.next();
            }
            ElkNode box = boxIter.next();
            double oldHeight = box.getHeight();
            box.setHeight(rowHeight);
            double newHeight = rowHeight;
            if (boxIter.nextIndex() == nextRowIndex) {
                double newWidth = broadestRow - xpos - padding.getRight();
                double oldWidth = box.getWidth();
                box.setWidth(newWidth);
                // Content alignment
                ElkUtil.translate(box, new KVector(newWidth, newHeight), new KVector(oldWidth, oldHeight));
            }
            xpos += box.getWidth() + minSpacing;
        }
    }
    // return parent size
    return new KVector(broadestRow, totalHeight);
}
Also used : ElkNode(org.eclipse.elk.graph.ElkNode) KVector(org.eclipse.elk.core.math.KVector) LinkedList(java.util.LinkedList)

Aggregations

KVector (org.eclipse.elk.core.math.KVector)292 KVectorChain (org.eclipse.elk.core.math.KVectorChain)52 ElkNode (org.eclipse.elk.graph.ElkNode)49 LNode (org.eclipse.elk.alg.layered.graph.LNode)39 LPort (org.eclipse.elk.alg.layered.graph.LPort)37 ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)36 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)35 Test (org.junit.Test)30 ElkEdge (org.eclipse.elk.graph.ElkEdge)28 ElkLabel (org.eclipse.elk.graph.ElkLabel)27 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)26 ElkPadding (org.eclipse.elk.core.math.ElkPadding)25 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)20 PortSide (org.eclipse.elk.core.options.PortSide)19 ElkPort (org.eclipse.elk.graph.ElkPort)18 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)17 LGraph (org.eclipse.elk.alg.layered.graph.LGraph)15 ArrayList (java.util.ArrayList)13 Layer (org.eclipse.elk.alg.layered.graph.Layer)12 LMargin (org.eclipse.elk.alg.layered.graph.LMargin)11