Search in sources :

Example 56 with ElkRectangle

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

the class EndLabelPostprocessor method processNode.

private void processNode(final LNode node) {
    assert node.hasProperty(InternalProperties.END_LABELS);
    // The node should have a non-empty list of label cells, or something went TERRIBLY WRONG!!!
    Map<LPort, LabelCell> endLabelCells = node.getProperty(InternalProperties.END_LABELS);
    assert !endLabelCells.isEmpty();
    KVector nodePos = node.getPosition();
    for (LabelCell labelCell : endLabelCells.values()) {
        ElkRectangle labelCellRect = labelCell.getCellRectangle();
        labelCellRect.move(nodePos);
        labelCell.applyLabelLayout();
    }
    // Remove label cells
    node.setProperty(InternalProperties.END_LABELS, null);
}
Also used : LabelCell(org.eclipse.elk.alg.common.nodespacing.cellsystem.LabelCell) LPort(org.eclipse.elk.alg.layered.graph.LPort) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Example 57 with ElkRectangle

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

the class FinalSplineBendpointsCalculator method calculateControlPointsSloppy.

/**
 * As opposed to the conservative strategy to insert control points (see
 * {@link #calculateControlPointsConservative(LEdge, SplineSegment)}), the sloppy version tries to use less control
 * points to make the splines curvier. The method handles only the case in which one of the two involved nodes is a
 * {@link SplineEdgeRouter#isNormalNode(LNode) normal} node.
 *
 * Let {@code e = (u,v)} be the edge for which control points are to be determined. The conservative strategy adds
 * control points {@code a,b,c,d} as depicted in the figure below. For a normal node {@code u}, it is checked if
 * {@code a,b} can be omitted. This is the case if the path of the resulting spline doesn't intersect a node that
 * lies above or below {@code u}. The same is checked for a regular node {@code v} and the control points
 * {@code c,d}. In case all control points could be omitted, a single control point is added halfway in between the
 * two nodes, where the y-coordinate is computed as implemented in
 * {@link #computeSloppyCenterY(LEdge, double, double)}. Note that if no control points can be omitted,
 * the same control points are used as with the conservative strategy.
 *
 * <pre>
 *                v
 *               ___
 *              |   |
 *    u     c--d|   |
 *   ___    |   |___|
 *  |   |   |
 *  |   |a--b
 *  |___|
 * </pre>
 *
 * To illustrate the three possible scenarios in which control points are omitted.
 * <pre>
 *   shortcut src              shortcut tgt            shortcut both
 * </pre>
 *
 * <pre>
 *               ___                      ___                     ___
 *              |   |                    |   |                   |   |
 *          +--+|   |                .---|   |               .---|   |
 *   ___    |   |___|         ___    |   |___|        ___    +   |___|
 *  |   |   |                |   |   |               |   |   |
 *  |   |---`                |   |+--+               |   |---`
 *  |___|                    |___|                   |___|
 * </pre>
 */
private void calculateControlPointsSloppy(final LEdge edge, final SplineSegment containingSegment) {
    EdgeInformation ei = containingSegment.edgeInformation.get(edge);
    assert ei.normalSourceNode || ei.normalTargetNode;
    double startXPos = containingSegment.boundingBox.x;
    double endXPos = containingSegment.boundingBox.x + containingSegment.boundingBox.width;
    final double ySourceAnchor = ei.startY;
    final double yTargetAnchor = ei.endY;
    final boolean edgePointsDownwards = ySourceAnchor < yTargetAnchor;
    // pre-compute a number of coordinates that we might use as control points
    final KVector sourceStraightCP = new KVector(startXPos, ySourceAnchor);
    final KVector targetStraightCP = new KVector(endXPos, yTargetAnchor);
    final double centerXPos = (startXPos + endXPos) / 2;
    final KVector sourceVerticalCP = new KVector(centerXPos, ySourceAnchor);
    final KVector targetVerticalCP = new KVector(centerXPos, yTargetAnchor);
    // evaluate if a rather direct curve is possible
    double centerYPos = computeSloppyCenterY(edge, ySourceAnchor, yTargetAnchor);
    KVector v1 = containingSegment.sourcePort.getAbsoluteAnchor();
    KVector v2 = new KVector(centerXPos, centerYPos);
    KVector v3 = containingSegment.targetPort.getAbsoluteAnchor();
    // approx will be an array holding two values, the zeroth of which represents the
    // center of the curve
    KVector[] approx = ElkMath.approximateBezierSegment(2, v1, v2, v3);
    boolean shortCutSource = false;
    final LNode src = containingSegment.sourcePort.getNode();
    // the node's layer)
    if (src != null && src.getLayer() != null && ei.normalSourceNode) {
        // possible intersections must only be checked if there are nodes
        // with which the edge could potentially intersect
        final boolean needToCheckSrc = edgePointsDownwards && src.id < src.getLayer().getNodes().size() - 1 || !edgePointsDownwards && src.id > 0;
        if (!needToCheckSrc) {
            shortCutSource = true;
        } else {
            // check within src's layer
            if (needToCheckSrc) {
                int neighborIndex = src.id;
                if (edgePointsDownwards) {
                    neighborIndex++;
                } else {
                    neighborIndex--;
                }
                LNode neighbor = src.getLayer().getNodes().get(neighborIndex);
                ElkRectangle box = nodeToBoundingBox(neighbor);
                shortCutSource = !(ElkMath.intersects(box, v1, approx[0]) || ElkMath.contains(box, v1, approx[0]));
            }
        }
    }
    boolean shortCutTarget = false;
    final LNode tgt = containingSegment.targetPort.getNode();
    // see comment above
    if (tgt != null && tgt.getLayer() != null && ei.normalTargetNode) {
        final boolean needToCheckTgt = edgePointsDownwards && tgt.id > 0 || !edgePointsDownwards && tgt.id < tgt.getLayer().getNodes().size() - 1;
        // tgt's layer
        if (!needToCheckTgt) {
            shortCutTarget = true;
        } else {
            int neighborIndex = tgt.id;
            if (edgePointsDownwards) {
                neighborIndex--;
            } else {
                neighborIndex++;
            }
            LNode neighbor = tgt.getLayer().getNodes().get(neighborIndex);
            ElkRectangle box = nodeToBoundingBox(neighbor);
            shortCutTarget = !(ElkMath.intersects(box, approx[0], v3) || ElkMath.contains(box, approx[0], v3));
        }
    }
    // now add the control points
    if (shortCutSource && shortCutTarget) {
        edge.getBendPoints().add(v2);
    }
    if (!shortCutSource) {
        edge.getBendPoints().addAll(sourceStraightCP, sourceVerticalCP);
    }
    if (!shortCutTarget) {
        edge.getBendPoints().addAll(targetVerticalCP, targetStraightCP);
    }
}
Also used : LNode(org.eclipse.elk.alg.layered.graph.LNode) EdgeInformation(org.eclipse.elk.alg.layered.p5edges.splines.SplineSegment.EdgeInformation) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Example 58 with ElkRectangle

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

the class LabelAndNodeSizeProcessor method placeExternalPortDummyLabels.

/**
 * Places the labels of the given external port dummy such that it results in correct node margins later on that
 * will reserve enough space for the labels to be placed once label and node placement is called on the graph.
 */
private void placeExternalPortDummyLabels(final LNode dummy, final Set<PortLabelPlacement> graphPortLabelPlacement, final boolean placeNextToPortIfPossible, final boolean treatAsGroup) {
    double labelPortSpacing = dummy.getProperty(LayeredOptions.SPACING_LABEL_PORT);
    double labelLabelSpacing = dummy.getProperty(LayeredOptions.SPACING_LABEL_LABEL);
    KVector dummySize = dummy.getSize();
    // External port dummies have exactly one port (see ElkGraphImporter)
    LPort dummyPort = dummy.getPorts().get(0);
    KVector dummyPortPos = dummyPort.getPosition();
    ElkRectangle portLabelBox = computePortLabelBox(dummyPort, labelLabelSpacing);
    if (portLabelBox == null) {
        return;
    }
    // TODO We could handle FIXED here as well
    if (graphPortLabelPlacement.contains(PortLabelPlacement.INSIDE)) {
        // (port label placement has to support this case first, though)
        switch(dummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
            case NORTH:
                portLabelBox.x = (dummySize.x - portLabelBox.width) / 2 - dummyPortPos.x;
                portLabelBox.y = labelPortSpacing;
                break;
            case SOUTH:
                portLabelBox.x = (dummySize.x - portLabelBox.width) / 2 - dummyPortPos.x;
                portLabelBox.y = -labelPortSpacing - portLabelBox.height;
                break;
            case EAST:
                if (labelNextToPort(dummyPort, true, placeNextToPortIfPossible)) {
                    double labelHeight = treatAsGroup ? portLabelBox.height : dummyPort.getLabels().get(0).getSize().y;
                    portLabelBox.y = (dummySize.y - labelHeight) / 2 - dummyPortPos.y;
                } else {
                    portLabelBox.y = dummySize.y + labelPortSpacing - dummyPortPos.y;
                }
                portLabelBox.x = -labelPortSpacing - portLabelBox.width;
                break;
            case WEST:
                if (labelNextToPort(dummyPort, true, placeNextToPortIfPossible)) {
                    double labelHeight = treatAsGroup ? portLabelBox.height : dummyPort.getLabels().get(0).getSize().y;
                    portLabelBox.y = (dummySize.y - labelHeight) / 2 - dummyPortPos.y;
                } else {
                    portLabelBox.y = dummySize.y + labelPortSpacing - dummyPortPos.y;
                }
                portLabelBox.x = labelPortSpacing;
                break;
        }
    } else if (graphPortLabelPlacement.contains(PortLabelPlacement.OUTSIDE)) {
        switch(dummy.getProperty(InternalProperties.EXT_PORT_SIDE)) {
            case NORTH:
            case SOUTH:
                portLabelBox.x = dummyPortPos.x + labelPortSpacing;
                break;
            case EAST:
            case WEST:
                if (labelNextToPort(dummyPort, false, placeNextToPortIfPossible)) {
                    double labelHeight = treatAsGroup ? portLabelBox.height : dummyPort.getLabels().get(0).getSize().y;
                    portLabelBox.y = (dummySize.y - labelHeight) / 2 - dummyPortPos.y;
                } else {
                    portLabelBox.y = dummyPortPos.y + labelPortSpacing;
                }
                break;
        }
    }
    // Place the labels
    double currentY = portLabelBox.y;
    for (LLabel label : dummyPort.getLabels()) {
        KVector labelPos = label.getPosition();
        labelPos.x = portLabelBox.x;
        labelPos.y = currentY;
        currentY += label.getSize().y + labelLabelSpacing;
    }
}
Also used : LLabel(org.eclipse.elk.alg.layered.graph.LLabel) LPort(org.eclipse.elk.alg.layered.graph.LPort) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Example 59 with ElkRectangle

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

the class ComponentsCompactor method transformLGraph.

// ------------------------------------------------------------------------------------------------
// private API
// ------------------------------------------------------------------------------------------------
/**
 * Converts a {@link LGraph} into an component, i.e. a set of rectangles
 * describing the space occupied by the component and a set of external extensions.
 */
private IComponent<LNode, Set<LEdge>> transformLGraph(final LGraph graph) {
    InternalComponent component = new InternalComponent(graph);
    if (!component.containsRegularNodes) {
        createDummyNode(graph);
    }
    // #1 convert the nodes to hull points
    Hullpoints hullPoints = componentHullPoints(graph);
    // #2 convert external edges,
    // while doing this, add further hull points contributed by inner segments
    // and remember extreme points of external segments
    Multimap<Direction, LEdge> externalExtensions = HashMultimap.create();
    OuterSegments outerSegments = new OuterSegments();
    for (LNode node : graph.getLayerlessNodes()) {
        for (LEdge edge : node.getOutgoingEdges()) {
            if (isExternalEdge(edge)) {
                IExternalExtension<LEdge> iee = transformLEdge(edge, hullPoints, outerSegments);
                externalExtensions.put(iee.getDirection(), iee.getRepresentative());
            }
        }
    }
    // #3 create the common external extensions for this component
    // (there can be 4 per component, one in each direction)
    List<InternalUnionExternalExtension> extensions = Lists.newArrayList();
    for (PortSide ps : component.getExternalExtensionSides()) {
        double min = outerSegments.min[ps.ordinal()];
        double max = outerSegments.max[ps.ordinal()];
        double extent = outerSegments.extent[ps.ordinal()];
        ElkRectangle extension = null;
        ElkRectangle placeholder = null;
        switch(ps) {
            case WEST:
                extension = new ElkRectangle(graphTopLeft.x, min, hullPoints.topLeft.x - graphTopLeft.x, max - min);
                placeholder = new ElkRectangle(graphTopLeft.x, min, extent, max - min);
                hullPoints.add(extension.getTopRight());
                hullPoints.add(extension.getBottomRight());
                break;
            case EAST:
                extension = new ElkRectangle(hullPoints.bottomRight.x, min, graphBottomRight.x - hullPoints.bottomRight.x, max - min);
                placeholder = new ElkRectangle(graphBottomRight.x - extent, min, extent, max - min);
                hullPoints.add(extension.getTopLeft());
                hullPoints.add(extension.getBottomLeft());
                break;
            case NORTH:
                extension = new ElkRectangle(min, graphTopLeft.y, max - min, hullPoints.topLeft.y - graphTopLeft.y);
                placeholder = new ElkRectangle(min, graphTopLeft.y, max - min, extent);
                hullPoints.add(extension.getBottomLeft());
                hullPoints.add(extension.getBottomRight());
                break;
            case SOUTH:
                extension = new ElkRectangle(min, hullPoints.bottomRight.y, max - min, graphBottomRight.y - hullPoints.bottomRight.y);
                placeholder = new ElkRectangle(min, graphBottomRight.y - extent, max - min, extent);
                hullPoints.add(extension.getTopLeft());
                hullPoints.add(extension.getTopRight());
                break;
        }
        // instantiate the external extension object
        if (extension != null) {
            InternalUnionExternalExtension iuee = new InternalUnionExternalExtension();
            iuee.side = ps;
            iuee.extension = extension;
            iuee.placeholder = placeholder;
            iuee.edges = Sets.newHashSet(externalExtensions.get(portSideToDirection(ps)));
            extensions.add(iuee);
        }
    }
    // #4 calculate the hull for the component
    component.externalExtensions.addAll(extensions);
    component.rectilinearConvexHull = RectilinearConvexHull.of(hullPoints).splitIntoRectangles();
    return component;
}
Also used : LEdge(org.eclipse.elk.alg.layered.graph.LEdge) Direction(org.eclipse.elk.core.options.Direction) LNode(org.eclipse.elk.alg.layered.graph.LNode) PortSide(org.eclipse.elk.core.options.PortSide) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Example 60 with ElkRectangle

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

the class RectilinearConvexHullTest method visualize.

private static void visualize(final List<Point> points, final RectilinearConvexHull rch) {
    KVector offset = new KVector(10, 10);
    double scale = 10;
    @SuppressWarnings("serial") JPanel p = new JPanel() {

        public void paint(java.awt.Graphics g) {
            super.paint(g);
            g.setColor(Color.DARK_GRAY);
            g.fillPolygon(toPolygon(rch, offset, scale));
            g.setColor(Color.GRAY);
            for (Point p : points) {
                g.fillRect((int) (p.x * scale + offset.x) - 1, (int) (p.y * scale + offset.y) - 1, 3, 3);
            }
            g.setColor(Color.PINK);
            for (ElkRectangle r : rch.splitIntoRectangles()) {
                g.drawRect((int) (r.x * scale + offset.x), (int) ((r.y) * scale + offset.y), (int) (r.width * scale), (int) (r.height * scale));
            }
            g.setColor(Color.GRAY);
        }
    };
    JFrame f = new JFrame();
    f.setSize(1500, 1500);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
    f.getContentPane().add(p);
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
Also used : JPanel(javax.swing.JPanel) JFrame(javax.swing.JFrame) Point(org.eclipse.elk.alg.common.Point) KVector(org.eclipse.elk.core.math.KVector) ElkRectangle(org.eclipse.elk.core.math.ElkRectangle)

Aggregations

ElkRectangle (org.eclipse.elk.core.math.ElkRectangle)82 KVector (org.eclipse.elk.core.math.KVector)33 Test (org.junit.Test)27 Direction (org.eclipse.elk.core.options.Direction)18 CGraph (org.eclipse.elk.alg.layered.compaction.oned.CGraph)17 ElkPadding (org.eclipse.elk.core.math.ElkPadding)9 PortContext (org.eclipse.elk.alg.common.nodespacing.internal.PortContext)8 LabelCell (org.eclipse.elk.alg.common.nodespacing.cellsystem.LabelCell)7 CGroup (org.eclipse.elk.alg.layered.compaction.oned.CGroup)6 Point (org.eclipse.elk.alg.common.Point)4 LMargin (org.eclipse.elk.alg.layered.graph.LMargin)4 LPort (org.eclipse.elk.alg.layered.graph.LPort)4 ElkNode (org.eclipse.elk.graph.ElkNode)4 RectilinearConvexHull (org.eclipse.elk.alg.common.RectilinearConvexHull)3 AtomicCell (org.eclipse.elk.alg.common.nodespacing.cellsystem.AtomicCell)3 RectangleStripOverlapRemover (org.eclipse.elk.alg.common.overlaps.RectangleStripOverlapRemover)3 LEdge (org.eclipse.elk.alg.layered.graph.LEdge)3 LLabel (org.eclipse.elk.alg.layered.graph.LLabel)3 LNode (org.eclipse.elk.alg.layered.graph.LNode)3 Random (java.util.Random)2