Search in sources :

Example 71 with ElkPort

use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.

the class ElkGraphBuilder method createPort.

/**
 * @param parent
 * @param side
 * @param dockedElement
 * @param portBorderOffset additional offset from the border. Used to set the ELK port border offset for nested ports.
 * @param mapping
 * @return
 */
private ElkPort createPort(final ElkNode parent, final PortSide side, final DiagramElement dockedElement, final double portBorderOffset, final LayoutMapping mapping) {
    final List<DiagramElement> dockedChildren = getDockedChildren(dockedElement);
    final Dimension untransformedGraphicSize = layoutInfoProvider.getPortGraphicSize(dockedElement);
    final Dimension transformedGraphicSize = transformDimension(untransformedGraphicSize, side);
    final Dimension untransformedLabelsSize = layoutInfoProvider.getDockedElementLabelsSize(dockedElement);
    final Dimension transformedLabelsSize = transformDimension(untransformedLabelsSize, side);
    // Create child ports and sort them by the size of the dimension parallel to the docked side
    final List<ElkPort> childPorts = dockedChildren.stream().map(ce -> createPort(parent, side, ce, getOrthogonalSize(transformedGraphicSize, side), mapping)).sorted((p1, p2) -> Double.compare(getSize(p1, side), getSize(p1, side))).collect(Collectors.toCollection(ArrayList::new));
    // If the port has child ports, then we assume it is a feature group.
    // The child ports are split into two bins and positioned such that they do not overlap the center of the feature group.
    // The parent port will be sized accordingly.
    final double maxChildBinSize;
    if (childPorts.size() > 0) {
        // Split the ports into two lists which have roughly equal heights/widths(depending on the docked side)
        double[] binSize = { 0.0, 0.0 };
        @SuppressWarnings("unchecked") final List<ElkPort>[] binLists = new ArrayList[] { new ArrayList<>(), new ArrayList<>() };
        for (final ElkPort childPort : childPorts) {
            final double size = getSize(childPort, side);
            final int binIndex = binSize[0] <= binSize[1] ? 0 : 1;
            binLists[binIndex].add(childPort);
            binSize[binIndex] += size + paddingSize;
        }
        // Determine the total size of the feature
        maxChildBinSize = Math.max(binSize[0], binSize[1]);
        // Set the position of the port relative to its parent because the size and position of the parent will be selected after its children are sized.
        for (int i = 0; i < 2; i++) {
            double childPosition = transformedLabelsSize.height + i * (maxChildBinSize + transformedGraphicSize.height);
            for (final ElkPort childPort : binLists[i]) {
                setPositionAlongSide(childPort, side, childPosition);
                childPosition += getSize(childPort, side) + paddingSize;
            }
        }
    } else {
        maxChildBinSize = 0.0;
    }
    // Size the parent port based on the bin size.
    final double newGraphicSize = 2.0 * maxChildBinSize + transformedGraphicSize.height;
    final double totalSize = transformedLabelsSize.height + newGraphicSize;
    final ElkPort newPort = ElkGraphUtil.createPort(parent);
    mapping.getGraphMap().put(newPort, dockedElement);
    newPort.setProperty(CoreOptions.PORT_SIDE, side);
    // Determine max orthogonal size of children
    double maxChildOrthogonalSize = 0;
    for (final ElkPort childPort : childPorts) {
        maxChildOrthogonalSize = Math.max(maxChildOrthogonalSize, getOrthogonalSize(childPort, side));
    }
    // Determine size and position
    final Dimension newSize;
    if (DiagramElementPredicates.isResizeable(dockedElement)) {
        newSize = new Dimension(Math.max(untransformedLabelsSize.width, maxChildOrthogonalSize + getOrthogonalSize(transformedGraphicSize, side)), totalSize);
    } else {
        newSize = new Dimension(Math.max(untransformedLabelsSize.width, untransformedGraphicSize.width), transformedLabelsSize.height + untransformedGraphicSize.height);
    }
    // final graph.
    if (omitNestedPorts) {
        for (final ElkPort childPort : childPorts) {
            mapping.getGraphMap().remove(childPort);
            EcoreUtil.remove(childPort);
        }
    }
    final Dimension transformedNewSize = transformDimension(newSize, side);
    newPort.setWidth(transformedNewSize.width);
    newPort.setHeight(transformedNewSize.height);
    // Set port border offset
    if (PortSide.SIDES_NORTH_SOUTH.contains(side)) {
        newPort.setProperty(CoreOptions.PORT_BORDER_OFFSET, -newPort.getHeight() - portBorderOffset);
    } else {
        newPort.setProperty(CoreOptions.PORT_BORDER_OFFSET, -newPort.getWidth() - portBorderOffset);
    }
    // Set the port anchor based on where the actual graphic will be.
    final Dimension transformedPortAnchor = transformDimension(new Dimension(untransformedGraphicSize.width / 2, transformedLabelsSize.height + maxChildBinSize + untransformedGraphicSize.height / 2.0), side);
    newPort.setProperty(CoreOptions.PORT_ANCHOR, new KVector(transformedPortAnchor.width, transformedPortAnchor.height));
    return newPort;
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) PortSide(org.eclipse.elk.core.options.PortSide) Dimension(org.osate.ge.graphics.Dimension) HashMap(java.util.HashMap) LayoutMapping(org.eclipse.elk.core.service.LayoutMapping) ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) ArrayList(java.util.ArrayList) Style(org.osate.ge.graphics.Style) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) ElkPadding(org.eclipse.elk.core.math.ElkPadding) Map(java.util.Map) AgeShape(org.osate.ge.graphics.internal.AgeShape) DiagramElementPredicates(org.osate.ge.internal.diagram.runtime.DiagramElementPredicates) HierarchyHandling(org.eclipse.elk.core.options.HierarchyHandling) EnumSet(java.util.EnumSet) PortConstraints(org.eclipse.elk.core.options.PortConstraints) ElkLabel(org.eclipse.elk.graph.ElkLabel) Predicate(java.util.function.Predicate) KVector(org.eclipse.elk.core.math.KVector) Collection(java.util.Collection) Label(org.osate.ge.graphics.internal.Label) SizeOptions(org.eclipse.elk.core.options.SizeOptions) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) Collectors(java.util.stream.Collectors) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) DiagramElementUtil(org.osate.ge.internal.util.DiagramElementUtil) DockingPosition(org.osate.ge.DockingPosition) Objects(java.util.Objects) AgeDiagram(org.osate.ge.internal.diagram.runtime.AgeDiagram) List(java.util.List) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) NodeLabelPlacement(org.eclipse.elk.core.options.NodeLabelPlacement) Direction(org.eclipse.elk.core.options.Direction) Entry(java.util.Map.Entry) Optional(java.util.Optional) ElkEdge(org.eclipse.elk.graph.ElkEdge) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) ElkGraphUtil(org.eclipse.elk.graph.util.ElkGraphUtil) StyleProvider(org.osate.ge.internal.diagram.runtime.styling.StyleProvider) Collections(java.util.Collections) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) ElkPort(org.eclipse.elk.graph.ElkPort) ArrayList(java.util.ArrayList) Dimension(org.osate.ge.graphics.Dimension) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) ArrayList(java.util.ArrayList) List(java.util.List) KVector(org.eclipse.elk.core.math.KVector)

Example 72 with ElkPort

use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.

the class ElkGraphBuilder method addPositionOffsets.

/**
 * Adds position offset along axis for the specified port, graphic port, and children
 * @param de
 * @param offset
 * @param side
 * @param mapping
 */
private void addPositionOffsets(final DiagramElement de, final double offset, final PortSide side, final LayoutMapping mapping) {
    final ElkPort childPort = (ElkPort) mapping.getGraphMap().inverse().get(de);
    final double newPosition = addPositionOffset(childPort, side, offset);
    // Only attempt to update child ports if nested ports are not being omitted.
    if (!omitNestedPorts) {
        de.getChildren().stream().filter(child -> child.getGraphic() instanceof AgeShape && !(child.getGraphic() instanceof Label) && child.getDockArea() != null).forEach(childDiagramElement -> addPositionOffsets(childDiagramElement, newPosition, side, mapping));
    }
}
Also used : CoreOptions(org.eclipse.elk.core.options.CoreOptions) DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) PortSide(org.eclipse.elk.core.options.PortSide) Dimension(org.osate.ge.graphics.Dimension) HashMap(java.util.HashMap) LayoutMapping(org.eclipse.elk.core.service.LayoutMapping) ElkNode(org.eclipse.elk.graph.ElkNode) ElkPort(org.eclipse.elk.graph.ElkPort) ArrayList(java.util.ArrayList) Style(org.osate.ge.graphics.Style) DockArea(org.osate.ge.internal.diagram.runtime.DockArea) ElkPadding(org.eclipse.elk.core.math.ElkPadding) Map(java.util.Map) AgeShape(org.osate.ge.graphics.internal.AgeShape) DiagramElementPredicates(org.osate.ge.internal.diagram.runtime.DiagramElementPredicates) HierarchyHandling(org.eclipse.elk.core.options.HierarchyHandling) EnumSet(java.util.EnumSet) PortConstraints(org.eclipse.elk.core.options.PortConstraints) ElkLabel(org.eclipse.elk.graph.ElkLabel) Predicate(java.util.function.Predicate) KVector(org.eclipse.elk.core.math.KVector) Collection(java.util.Collection) Label(org.osate.ge.graphics.internal.Label) SizeOptions(org.eclipse.elk.core.options.SizeOptions) EcoreUtil(org.eclipse.emf.ecore.util.EcoreUtil) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) Collectors(java.util.stream.Collectors) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) DiagramElementUtil(org.osate.ge.internal.util.DiagramElementUtil) DockingPosition(org.osate.ge.DockingPosition) Objects(java.util.Objects) AgeDiagram(org.osate.ge.internal.diagram.runtime.AgeDiagram) List(java.util.List) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) NodeLabelPlacement(org.eclipse.elk.core.options.NodeLabelPlacement) Direction(org.eclipse.elk.core.options.Direction) Entry(java.util.Map.Entry) Optional(java.util.Optional) ElkEdge(org.eclipse.elk.graph.ElkEdge) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) ElkGraphUtil(org.eclipse.elk.graph.util.ElkGraphUtil) StyleProvider(org.osate.ge.internal.diagram.runtime.styling.StyleProvider) Collections(java.util.Collections) DiagramNode(org.osate.ge.internal.diagram.runtime.DiagramNode) ElkPort(org.eclipse.elk.graph.ElkPort) AgeShape(org.osate.ge.graphics.internal.AgeShape) ElkLabel(org.eclipse.elk.graph.ElkLabel) Label(org.osate.ge.graphics.internal.Label)

Example 73 with ElkPort

use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.

the class ElkGraphBuilder method createAndPositionPorts.

// Create and position ports for an elk node
private void createAndPositionPorts(final ElkNode parentNode, final List<DiagramElement> dockedDiagramElements, final PortSide side, final double additionalPadding, final LayoutMapping mapping, final boolean parentHasNestedPorts) {
    // Create and position ports
    double position = paddingSize + additionalPadding;
    double maxPosition = position;
    for (final DiagramElement dockedElement : dockedDiagramElements) {
        final ElkPort newPort = createPort(parentNode, side, dockedElement, 0, mapping);
        // Determine if the position has been provided by the fixed port position provider
        if (parentHasNestedPorts) {
            final Double overridePosition = fixedPortPositionProvider.getPortPosition(dockedElement);
            if (overridePosition != null) {
                position = overridePosition;
            }
        }
        setPositionAlongSide(newPort, side, position);
        addPositionOffsets((DiagramElement) mapping.getGraphMap().get(newPort), 0.0, side, mapping);
        position += getSize(newPort, side) + paddingSize;
        // The max position may not always be increasing because the fixed port position provider may override the position.
        maxPosition = Math.max(maxPosition, position);
    }
    // Additional padding
    maxPosition += 5;
    if (parentHasNestedPorts) {
        // Create a dummy port so that the last port on the side will have the minimum padding
        final ElkPort newPort = ElkGraphUtil.createPort(parentNode);
        newPort.setProperty(CoreOptions.PORT_SIDE, side);
        newPort.setY(maxPosition);
        newPort.setWidth(0);
        newPort.setHeight(0);
    }
}
Also used : DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) ElkPort(org.eclipse.elk.graph.ElkPort)

Example 74 with ElkPort

use of org.eclipse.elk.graph.ElkPort in project osate2 by osate.

the class ElkGraphBuilder method createElkGraphElementsForConnections.

/**
 * Creates ELK edges for connection diagram nodes which are descendants of the specified node.
 * Even though the results of the ELK edge routing are not used, it is still important because it affects the placements of shapes.
 */
private void createElkGraphElementsForConnections(final DiagramNode dn, final LayoutMapping mapping) {
    for (final DiagramElement de : dn.getChildren()) {
        if (de.getGraphic() instanceof AgeConnection) {
            final AgeConnection connection = (AgeConnection) de.getGraphic();
            // Flow indicators are represented by a node in the container which has a port and an edge connecting that port to the starting element
            final ElkConnectableShape edgeStart = getConnectableShape(de.getStartElement(), mapping);
            ElkConnectableShape edgeEnd = null;
            if (connection.isFlowIndicator) {
                // Find the first undocked ancestor for the flow indicator
                final DiagramElement undockedContainer = DiagramElementUtil.getUndockedDiagramElement(de.getParent());
                if (undockedContainer == null) {
                    // Ignore the flow indicator if unable to find a containing element which isn't docked.
                    continue;
                }
                // Find the ELK shape for the ancestor
                final ElkConnectableShape endContainer = getConnectableShape(undockedContainer, mapping);
                if (!(endContainer instanceof ElkNode)) {
                    // Ignore the flow indicator if the container isn't a node.
                    continue;
                }
                // Create the node for the end of the flow indicator
                final ElkNode endNode = ElkGraphUtil.createNode((ElkNode) endContainer);
                endContainer.setDimensions(0, 0);
                endNode.setProperty(CoreOptions.NODE_SIZE_CONSTRAINTS, EnumSet.noneOf(SizeConstraint.class));
                endNode.setProperty(CoreOptions.NODE_SIZE_OPTIONS, EnumSet.noneOf(SizeOptions.class));
                // Create port
                final ElkPort endPort = ElkGraphUtil.createPort(endNode);
                endPort.setProperty(CoreOptions.PORT_SIDE, PortSide.WEST);
                endPort.setX(0);
                endPort.setY(0);
                endPort.setWidth(0);
                endPort.setHeight(0);
                edgeEnd = endPort;
            } else {
                edgeEnd = getConnectableShape(de.getEndElement(), mapping);
            }
            if (edgeStart != null && edgeEnd != null) {
                final ElkConnectableShape start = edgeStart;
                final ElkConnectableShape end = edgeEnd;
                boolean insideSelfLoopsYo = true;
                // An example of this sort of edge is a steady state state transition in the EMV2
                if (start == end) {
                    insideSelfLoopsYo = false;
                }
                final ElkEdge newEdge = ElkGraphUtil.createSimpleEdge(start, end);
                // Allow edges with the same start and end shape because they layout as intended.
                if (start == end && start instanceof ElkPort) {
                    continue;
                }
                // Ensure the edge has at least one section. Fixes NPE that can occur when laying out connections
                // with the same source and destination port.
                ElkGraphUtil.createEdgeSection(newEdge);
                newEdge.setProperty(CoreOptions.INSIDE_SELF_LOOPS_YO, insideSelfLoopsYo);
                mapping.getGraphMap().put(newEdge, de);
                createElkLabels(de, newEdge, mapping);
                // along with other edges
                if (connection.isFlowIndicator && newEdge.getLabels().isEmpty()) {
                    final ElkLabel spacingLabel = createElkLabel(newEdge, "<Spacing>", new Dimension(10, 10));
                    if (!layoutConnectionLabels) {
                        spacingLabel.setProperty(CoreOptions.NO_LAYOUT, true);
                    }
                }
            }
        }
        createElkGraphElementsForConnections(de, mapping);
    }
}
Also used : DiagramElement(org.osate.ge.internal.diagram.runtime.DiagramElement) AgeConnection(org.osate.ge.graphics.internal.AgeConnection) ElkNode(org.eclipse.elk.graph.ElkNode) SizeOptions(org.eclipse.elk.core.options.SizeOptions) ElkLabel(org.eclipse.elk.graph.ElkLabel) ElkPort(org.eclipse.elk.graph.ElkPort) Dimension(org.osate.ge.graphics.Dimension) ElkConnectableShape(org.eclipse.elk.graph.ElkConnectableShape) SizeConstraint(org.eclipse.elk.core.options.SizeConstraint) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Example 75 with ElkPort

use of org.eclipse.elk.graph.ElkPort in project glsp-server by eclipse-glsp.

the class ElkLayoutEngine method processChildren.

/*
    * Transform the children of a sprotty model element to their ELK graph
    * counterparts.
    */
@SuppressWarnings({ "checkstyle:CyclomaticComplexity", "checkstyle:NestedIfDepth" })
protected int processChildren(final GModelElement sParent, final ElkGraphElement elkParent, final LayoutContext context) {
    int childrenCount = 0;
    if (sParent.getChildren() != null) {
        for (GModelElement schild : sParent.getChildren()) {
            context.parentMap.put(schild, sParent);
            ElkGraphElement elkChild = null;
            if (shouldInclude(schild, sParent, elkParent, context)) {
                if (schild instanceof GNode) {
                    GNode snode = (GNode) schild;
                    ElkNode elkNode = createNode(snode);
                    if (elkParent instanceof ElkNode) {
                        elkNode.setParent((ElkNode) elkParent);
                        childrenCount++;
                    }
                    context.shapeMap.put(snode, elkNode);
                    elkChild = elkNode;
                } else if (schild instanceof GPort) {
                    GPort gport = (GPort) schild;
                    ElkPort elkPort = createPort(gport);
                    if (elkParent instanceof ElkNode) {
                        elkPort.setParent((ElkNode) elkParent);
                        childrenCount++;
                    }
                    context.shapeMap.put(gport, elkPort);
                    elkChild = elkPort;
                } else if (schild instanceof GEdge) {
                    GEdge gedge = (GEdge) schild;
                    ElkEdge elkEdge = createEdge(gedge);
                    // The most suitable container for the edge is determined later
                    childrenCount++;
                    context.edgeMap.put(gedge, elkEdge);
                    elkChild = elkEdge;
                } else if (schild instanceof GLabel) {
                    GLabel glabel = (GLabel) schild;
                    ElkLabel elkLabel = createLabel(glabel);
                    elkLabel.setParent(elkParent);
                    childrenCount++;
                    context.shapeMap.put(glabel, elkLabel);
                    elkChild = elkLabel;
                }
            }
            int grandChildrenCount = processChildren(schild, elkChild != null ? elkChild : elkParent, context);
            childrenCount += grandChildrenCount;
            if (grandChildrenCount > 0 && sParent instanceof GLayouting && schild instanceof GBoundsAware) {
                handleClientLayout((GBoundsAware) schild, (GLayouting) sParent, elkParent, context);
            }
        }
    }
    return childrenCount;
}
Also used : GModelElement(org.eclipse.glsp.graph.GModelElement) GNode(org.eclipse.glsp.graph.GNode) ElkNode(org.eclipse.elk.graph.ElkNode) GPort(org.eclipse.glsp.graph.GPort) ElkPort(org.eclipse.elk.graph.ElkPort) GLabel(org.eclipse.glsp.graph.GLabel) GEdge(org.eclipse.glsp.graph.GEdge) GraphUtil.point(org.eclipse.glsp.graph.util.GraphUtil.point) ElkBendPoint(org.eclipse.elk.graph.ElkBendPoint) GPoint(org.eclipse.glsp.graph.GPoint) GBoundsAware(org.eclipse.glsp.graph.GBoundsAware) ElkLabel(org.eclipse.elk.graph.ElkLabel) GLayouting(org.eclipse.glsp.graph.GLayouting) ElkGraphElement(org.eclipse.elk.graph.ElkGraphElement) ElkEdge(org.eclipse.elk.graph.ElkEdge)

Aggregations

ElkPort (org.eclipse.elk.graph.ElkPort)76 ElkNode (org.eclipse.elk.graph.ElkNode)55 ElkEdge (org.eclipse.elk.graph.ElkEdge)32 ElkLabel (org.eclipse.elk.graph.ElkLabel)29 KVector (org.eclipse.elk.core.math.KVector)19 ElkConnectableShape (org.eclipse.elk.graph.ElkConnectableShape)15 ElkGraphElement (org.eclipse.elk.graph.ElkGraphElement)13 Test (org.junit.Test)13 ElkEdgeSection (org.eclipse.elk.graph.ElkEdgeSection)12 PortSide (org.eclipse.elk.core.options.PortSide)11 SizeConstraint (org.eclipse.elk.core.options.SizeConstraint)11 List (java.util.List)10 ElkPadding (org.eclipse.elk.core.math.ElkPadding)8 ElkGraphUtil (org.eclipse.elk.graph.util.ElkGraphUtil)8 Lists (com.google.common.collect.Lists)7 ArrayList (java.util.ArrayList)7 Collection (java.util.Collection)7 Collectors (java.util.stream.Collectors)7 Direction (org.eclipse.elk.core.options.Direction)7 PortConstraints (org.eclipse.elk.core.options.PortConstraints)7