use of org.eclipse.elk.graph.ElkGraphElement in project sirius-components by eclipse-sirius.
the class LayoutService method layout.
@Override
public Diagram layout(IEditingContext editingContext, Diagram diagram) {
ELKConvertedDiagram convertedDiagram = this.elkDiagramConverter.convert(diagram);
ElkNode elkDiagram = convertedDiagram.getElkDiagram();
// @formatter:off
var optionalDiagramDescription = this.representationDescriptionSearchService.findById(editingContext, diagram.getDescriptionId()).filter(DiagramDescription.class::isInstance).map(DiagramDescription.class::cast);
// @formatter:on
ISiriusWebLayoutConfigurator layoutConfigurator;
if (optionalDiagramDescription.isPresent()) {
var diagramDescription = optionalDiagramDescription.get();
elkDiagram = this.layoutConfiguratorRegistry.applyBeforeLayout(elkDiagram, editingContext, diagram, diagramDescription);
layoutConfigurator = this.layoutConfiguratorRegistry.getLayoutConfigurator(diagram, diagramDescription);
} else {
layoutConfigurator = this.layoutConfiguratorRegistry.getDefaultLayoutConfigurator();
}
ElkUtil.applyVisitors(elkDiagram, layoutConfigurator);
IGraphLayoutEngine engine = new RecursiveGraphLayoutEngine();
engine.layout(elkDiagram, new BasicProgressMonitor());
if (optionalDiagramDescription.isPresent()) {
var diagramDescription = optionalDiagramDescription.get();
elkDiagram = this.layoutConfiguratorRegistry.applyAfterLayout(elkDiagram, editingContext, diagram, diagramDescription);
}
Map<String, ElkGraphElement> id2ElkGraphElements = convertedDiagram.getId2ElkGraphElements();
Diagram layoutedDiagram = this.elkLayoutedDiagramProvider.getLayoutedDiagram(diagram, elkDiagram, id2ElkGraphElements);
if (this.logger.isDebugEnabled()) {
// @formatter:off
String json = ElkGraphJson.forGraph(elkDiagram).omitLayout(true).omitZeroDimension(true).omitZeroPositions(true).shortLayoutOptionKeys(false).prettyPrint(true).toJson();
// @formatter:on
this.logger.debug(json);
}
return layoutedDiagram;
}
use of org.eclipse.elk.graph.ElkGraphElement in project sirius-components by eclipse-sirius.
the class ELKDiagramConverter method convert.
@Override
public ELKConvertedDiagram convert(Diagram diagram) {
Diagram initializedDiagram = this.initializeDiagram(diagram);
ElkNode elkDiagram = this.convertDiagram(initializedDiagram);
Map<String, ElkGraphElement> id2ElkGraphElements = new HashMap<>();
Map<String, ElkConnectableShape> connectableShapeIndex = new LinkedHashMap<>();
initializedDiagram.getNodes().stream().forEach(node -> this.convertNode(node, elkDiagram, connectableShapeIndex, id2ElkGraphElements));
initializedDiagram.getEdges().stream().forEach(edge -> this.convertEdge(edge, elkDiagram, connectableShapeIndex, id2ElkGraphElements));
return new ELKConvertedDiagram(elkDiagram, id2ElkGraphElements);
}
use of org.eclipse.elk.graph.ElkGraphElement in project osate2 by osate.
the class DiagramElementLayoutUtil method layout.
private static void layout(final DiagramModification m, final Collection<? extends DiagramNode> nodesToLayout, final StyleProvider styleProvider, final LayoutInfoProvider layoutInfoProvider, final LayoutOptions options) {
Objects.requireNonNull(nodesToLayout, "nodesToLayout must not be null");
try {
// Layout the nodes
final RecursiveGraphLayoutEngine layoutEngine = new RecursiveGraphLayoutEngine();
for (final DiagramNode dn : nodesToLayout) {
LayoutMapping mapping;
ElkNode layoutGraph;
// Perform the first layout. This layout will not include nested ports. This will allow ELK additional flexibility when determining port
// placement.
mapping = ElkGraphBuilder.buildLayoutGraph(dn, styleProvider, layoutInfoProvider, options, !options.layoutPortsOnDefaultSides, ElkGraphBuilder.FixedPortPositionProvider.NO_OP);
layoutGraph = mapping.getLayoutGraph();
layoutGraph.setProperty(CoreOptions.ALGORITHM, LAYOUT_ALGORITHM);
applyProperties(dn, mapping);
LayoutDebugUtil.saveElkGraphToDebugProject(layoutGraph, "pass1");
layoutEngine.layout(layoutGraph, new BasicProgressMonitor());
// nested ports and performing edge routing.
if (layoutGraph.getProperty(AgeLayoutOptions.NESTED_PORTS_WERE_OMITTED)) {
final LayoutMapping initialLayoutMapping = mapping;
mapping = ElkGraphBuilder.buildLayoutGraph(dn, styleProvider, layoutInfoProvider, options, false, new ElkGraphBuilder.FixedPortPositionProvider() {
@Override
public PortSide getPortSide(final DiagramElement de) {
final ElkGraphElement ge = initialLayoutMapping.getGraphMap().inverse().get(de);
if (ge instanceof ElkPort) {
return ge.getProperty(CoreOptions.PORT_SIDE);
}
return null;
}
@Override
public Double getPortPosition(final DiagramElement de) {
final ElkGraphElement ge = initialLayoutMapping.getGraphMap().inverse().get(de);
if (ge instanceof ElkPort) {
final ElkPort port = (ElkPort) ge;
final PortSide ps = port.getProperty(CoreOptions.PORT_SIDE);
if (PortSide.SIDES_EAST_WEST.contains(ps)) {
return port.getY();
} else {
return port.getX();
}
}
return null;
}
});
layoutGraph = mapping.getLayoutGraph();
layoutGraph.setProperty(CoreOptions.ALGORITHM, LAYOUT_ALGORITHM);
applyProperties(dn, mapping);
LayoutDebugUtil.saveElkGraphToDebugProject(layoutGraph, "pass2");
layoutEngine.layout(layoutGraph, new BasicProgressMonitor());
}
LayoutDebugUtil.saveElkGraphToDebugProject(layoutGraph, "final");
applyShapeLayout(mapping, m);
applyConnectionLayout(mapping, m);
// Layout feature self loop connections. These are omitted from the ELK based layout.
dn.getAllDiagramNodes().filter(DiagramElementLayoutUtil::isFeatureSelfLoopConnection).map(DiagramElement.class::cast).forEachOrdered(de -> layoutFeatureSelfLoopConnection(de, m, layoutInfoProvider));
}
} catch (final RuntimeException ex) {
// If a layout error occurs, display the exception but do not rethrow. This is so that the operation that attempted to do the layout will continue.
// This is important because otherwise simple operations such a adding elements to the diagram will completely fail. Suppressing the error will
// degrade performance but allow the user to keep working and should ensure things stay in a valid state.
// It would be best for other parts of the code to handle exceptions properly to avoid entering into an invalid state but this is the best
// workaround.
final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "A layout error occured.", ex);
StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
}
}
use of org.eclipse.elk.graph.ElkGraphElement in project osate2 by osate.
the class ElkGraphBuilder method createElkLabels.
private void createElkLabels(final DiagramElement parentElement, final ElkGraphElement parentLayoutElement, final LayoutMapping mapping) {
// Don't create labels for ElkPort. The bounds of the port contain their labels.
if (parentLayoutElement instanceof ElkPort) {
return;
}
final boolean isConnection = parentElement.getGraphic() instanceof AgeConnection;
final Style style = styleProvider.getStyle(parentElement);
if (style.getPrimaryLabelVisible()) {
// Create Primary Label
if (parentElement.getLabelName() != null) {
final ElkLabel elkLabel = createElkLabel(parentLayoutElement, parentElement.getLabelName(), layoutInfoProvider.getPrimaryLabelSize(parentElement));
if (isConnection) {
if (!layoutConnectionLabels) {
elkLabel.setProperty(CoreOptions.NO_LAYOUT, true);
}
mapping.getGraphMap().put(elkLabel, new PrimaryConnectionLabelReference(parentElement));
}
}
}
// Create label for annotations which are part of the graphic configuration. These are only supported by non-connections.
if (!isConnection && parentElement.getGraphicalConfiguration().getAnnotation() != null) {
createElkLabel(parentLayoutElement, parentElement.getGraphicalConfiguration().getAnnotation(), layoutInfoProvider.getAnnotationLabelSize(parentElement));
}
// Create Secondary Labels
parentElement.getChildren().stream().filter(c -> c.getGraphic() instanceof Label).forEachOrdered(labelElement -> {
final ElkLabel elkLabel = createElkLabel(parentLayoutElement, labelElement.getLabelName(), layoutInfoProvider.getPrimaryLabelSize(labelElement));
if (isConnection) {
if (!layoutConnectionLabels) {
elkLabel.setProperty(CoreOptions.NO_LAYOUT, true);
}
mapping.getGraphMap().put(elkLabel, new SecondaryConnectionLabelReference(labelElement));
}
});
if (parentLayoutElement instanceof ElkNode) {
parentLayoutElement.setProperty(CoreOptions.NODE_LABELS_PLACEMENT, getNodeLabelPlacement(style));
}
}
use of org.eclipse.elk.graph.ElkGraphElement in project elk by eclipse.
the class GmfDiagramLayoutConnector method processConnections.
/**
* Creates new edges and takes care of the labels for each connection identified in the
* {@code buildLayoutGraphRecursively} method.
*
* @param mapping
* the layout mapping
*/
protected void processConnections(final LayoutMapping mapping) {
Map<EReference, ElkEdge> reference2EdgeMap = new HashMap<>();
for (ConnectionEditPart connection : mapping.getProperty(CONNECTIONS)) {
boolean isOppositeEdge = false;
Optional<EdgeLabelPlacement> edgeLabelPlacement = Optional.empty();
ElkEdge edge;
// Check whether the edge belongs to an Ecore reference, which may have opposites.
// This is required for the layout of Ecore diagrams, since the bend points of
// opposite references are kept synchronized by the editor.
EObject modelObject = connection.getNotationView().getElement();
if (modelObject instanceof EReference) {
EReference reference = (EReference) modelObject;
edge = reference2EdgeMap.get(reference.getEOpposite());
if (edge != null) {
edgeLabelPlacement = Optional.of(EdgeLabelPlacement.TAIL);
isOppositeEdge = true;
} else {
edge = ElkGraphUtil.createEdge(null);
reference2EdgeMap.put(reference, edge);
}
} else {
edge = ElkGraphUtil.createEdge(null);
}
BiMap<Object, ElkGraphElement> inverseGraphMap = mapping.getGraphMap().inverse();
// find a proper source node and source port
ElkGraphElement sourceElem;
EditPart sourceObj = connection.getSource();
if (sourceObj instanceof ConnectionEditPart) {
sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getSource());
if (sourceElem == null) {
sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getTarget());
}
} else {
sourceElem = inverseGraphMap.get(sourceObj);
}
ElkConnectableShape sourceShape = null;
ElkPort sourcePort = null;
ElkNode sourceNode = null;
if (sourceElem instanceof ElkNode) {
sourceNode = (ElkNode) sourceElem;
sourceShape = sourceNode;
} else if (sourceElem instanceof ElkPort) {
sourcePort = (ElkPort) sourceElem;
sourceNode = sourcePort.getParent();
sourceShape = sourcePort;
} else {
continue;
}
// find a proper target node and target port
ElkGraphElement targetElem;
EditPart targetObj = connection.getTarget();
if (targetObj instanceof ConnectionEditPart) {
targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getTarget());
if (targetElem == null) {
targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getSource());
}
} else {
targetElem = inverseGraphMap.get(targetObj);
}
ElkConnectableShape targetShape = null;
ElkNode targetNode = null;
ElkPort targetPort = null;
if (targetElem instanceof ElkNode) {
targetNode = (ElkNode) targetElem;
targetShape = targetNode;
} else if (targetElem instanceof ElkPort) {
targetPort = (ElkPort) targetElem;
targetNode = targetPort.getParent();
targetShape = targetPort;
} else {
continue;
}
// calculate offset for edge and label coordinates
ElkNode edgeContainment = ElkGraphUtil.findLowestCommonAncestor(sourceNode, targetNode);
KVector offset = new KVector();
ElkUtil.toAbsolute(offset, edgeContainment);
if (!isOppositeEdge) {
// set source and target
edge.getSources().add(sourceShape);
edge.getTargets().add(targetShape);
// now that source and target are set, put the edge into the graph
edgeContainment.getContainedEdges().add(edge);
mapping.getGraphMap().put(edge, connection);
// store the current coordinates of the edge
setEdgeLayout(edge, connection, offset);
}
// process edge labels
processEdgeLabels(mapping, connection, edge, edgeLabelPlacement, offset);
}
}
Aggregations