Skip to content
Snippets Groups Projects
Commit cd4f91de authored by Nils Christian Ehmke's avatar Nils Christian Ehmke
Browse files

Modified the layout service; Updated the meta files from the example projects.

parent 323d4e24
No related branches found
No related tags found
No related merge requests found
#
#Mon Dec 03 14:49:14 CET 2012
#Wed Apr 10 14:08:23 CEST 2013
owner=Kieker-Administrator
layout=0 -675 -138 192 72;1 -379 -138 312 72;2 -21 -149 276 132;3 287 -137 252 108;4 983 -149 468 96;5 1841 -102 816 144;6 915 110 876 84;7 1837 98 840 120;8 2505 128 288 72;9 2499 -174 360 72;10 2917 -174 348 72;\#1.2 2.6 -191.5 -126.5 -191.5 -101.5;1.2 2.5 -191.5 -126.5 -191.5 -125.5;3.12 6.20 444.5 -137.5 444.5 121.5;4.0 10.R 1384.5 -155.5 1384.5 -256.5 2710.5 -256.5 2710.5 -162.5;4.15 5.16 1384.5 -119.5 1384.5 -90.5;5.1 10.R 2288.5 -132.5 2288.5 -256.5 2710.5 -256.5 2710.5 -162.5;5.17 8.26 2298.5 -96.5 2298.5 139.5;7.2 10.R 2288.5 79.5 2288.5 -93.5 2710.5 -93.5 2710.5 -162.5;8.3 10.R 2710.5 139.5 2710.5 -162.5;
last\ user=Kieker-Administrator
#
#Mon Dec 03 14:49:14 CET 2012
#Wed Apr 10 14:08:04 CEST 2013
owner=Kieker-Administrator
layout=0 -675 -155 192 72;1 -59 -167 336 84;2 651 -69 276 72;3 311 -57 276 84;4 311 -197 252 84;5 -403 -155 264 84;6 639 -201 252 72;\#1.2 4.8 140.5 -167.5 140.5 -185.5;1.3 3.5 140.5 -143.5 140.5 -45.5;4.9 6.14 480.5 -197.5 480.5 -189.5;
last\ user=Kieker-Administrator
......@@ -18,7 +18,6 @@ package kieker.webgui.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
......@@ -46,16 +45,17 @@ import de.cau.cs.kieler.kiml.util.KimlUtil;
import de.cau.cs.kieler.klay.layered.LayeredLayoutProvider;
/**
* This is a utility class providing a method to layout a graph from the graph flow editor. The method accepts two strings (one for the nodes, one for the edges)
* which are the result of specific javascript functions of the graph. For further information look into the API description of the flow editor itself.
* This class provides a single method to perform an auto layout on a given graph from the GraphFlow. The JavaScript GraphFlow throws an "autoLayout"-Event upon
* using the function autoLayout(). This event provides two Strings which may be used by this class' layoutGraph(nodes, edges) method. The return value can then be
* used as an argument for the GraphFlow's loadPositionsFromLayout(positions) function.
*
* @author row, Nils Christian Ehmke
* @author Robin Weiss, Nils Christian Ehmke
*/
@Service
public final class GraphLayoutServiceImpl implements IGraphLayoutService {
/**
* Default constructor. <b>Do not use this constructor. This bean is Spring managed.</b>
* Default constructor.
*/
public GraphLayoutServiceImpl() {
// No code necessary
......@@ -69,45 +69,52 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
@Override
public String layoutGraph(final String nodes, final String edges) throws GraphLayoutException {
try {
final LayoutInformation layoutInformation = GraphLayoutServiceImpl.assembleLayoutInformation(nodes, edges);
// Convert the given nodes and edges to a graph
final LayoutInformation layoutInformation = new LayoutInformation(nodes, edges);
// Create a progress monitor
// Perform the auto layout on the given graph.
final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor();
// Create the layout provider
final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider();
// Perform layout on the created graph
layoutProvider.doLayout(layoutInformation.getGraph(), progressMonitor);
// convert layouted graph positions to String
final String layoutedGraph = GraphLayoutServiceImpl.getPositions(layoutInformation);
final String bendPoints = GraphLayoutServiceImpl.getBendPoints(layoutInformation);
final StringBuilder sb = new StringBuilder("autoLayout#");
sb.append(layoutedGraph);
sb.append("#");
sb.append(bendPoints);
// Convert the layouted graph back into a string representation
final String layoutedGraph = layoutInformation.getPositions();
final String bendPoints = layoutInformation.getBendPoints();
final StringBuilder sb = new StringBuilder();
sb.append("autoLayout").append("#").append(layoutedGraph).append("#").append(bendPoints);
return sb.toString();
} catch (final NumberFormatException e) {
throw new GraphLayoutException("Invalid number format", e);
} catch (final Exception e) { // NOCS
throw new GraphLayoutException("Unknown Error!", e);
} catch (final NumberFormatException ex) {
throw new GraphLayoutException("Invalid Graph Information String!", ex);
} catch (final Exception ex) { // NOCS
throw new GraphLayoutException("Unknown Error!", ex);
}
}
/**
* Assembles the necessary layout information using the given parameters.
* A container for the layout information which will be assembled during the layout process.
*
* @author Robin Weiss, Nils Christian Ehmke
*/
private static final class LayoutInformation {
private final KNode graph;
private final Map<String, List<Object>> children;
private final Object[][] edges;
/**
* Creates a new instance of this class.
*
* @param nodesStr
* The string containing the information about the nodes.
* The string containing the nodes.
* @param edgesStr
* The string containing the information about the edges.
* The string containing the edges.
*
* @return An object containing the layout information for the graph.
* @throws GraphLayoutException
* If the given graph is empty or invalid.
*/
private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) throws NumberFormatException, GraphLayoutException {
public LayoutInformation(final String nodesStr, final String edgesStr) throws GraphLayoutException {
final int firstSemicolon = nodesStr.indexOf(';');
// if there is no semicolon, we got an empty graph
......@@ -117,16 +124,111 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
final int scale = Integer.parseInt(nodesStr.substring(0, firstSemicolon));
final String[] nodeInfo = GraphLayoutServiceImpl.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";"));
final String[] edgeInfo = GraphLayoutServiceImpl.correctEmptyArray(edgesStr.split(";"));
final String[] nodeInfo = LayoutInformation.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";"));
final String[] edgeInfo = LayoutInformation.correctEmptyArray(edgesStr.split(";"));
this.children = new HashMap<String, List<Object>>();
this.edges = new Object[edgeInfo.length][5];
this.graph = KimlUtil.createInitializedNode();
final Map<String, List<Object>> children = new HashMap<String, List<Object>>();
final Object[][] edges = new Object[edgeInfo.length][5];
final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges);
this.addNodes(scale, nodeInfo);
this.addEdges(edgeInfo);
// set graph layout options
final KShapeLayout layout = this.graph.getData(KShapeLayout.class);
// layout.setProperty(LayoutOptions.LAYOUT_HIERARCHY, true);
layout.setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL);
}
GraphLayoutServiceImpl.addNodes(scale, nodeInfo, layoutInformation);
GraphLayoutServiceImpl.addEdges(edgeInfo, layoutInformation);
return layoutInformation;
public KNode getGraph() {
return this.graph;
}
/**
* Reads the (layouted) positions of a constructed KGraph and writes them as integers to a string, separating each number with a space.
*
* @return The constructed string.
*/
public String getPositions() {
final StringBuilder sb = new StringBuilder();
for (final Entry<String, List<Object>> entry : this.children.entrySet()) {
final String id = entry.getKey();
final List<Object> nodeAndPortList = entry.getValue();
// Extract the position and size of the node
final KShapeLayout layout = ((KNode) nodeAndPortList.get(0)).getData(KShapeLayout.class);
final int x = Math.round(layout.getXpos() + (layout.getWidth() / 2));
final int y;
// HotFix: wrong nodeFamily position: needs to be half the height lower
if (nodeAndPortList.size() > 2) {
y = Math.round(layout.getYpos() + (layout.getHeight()));
} else {
y = Math.round(layout.getYpos() + (layout.getHeight() / 2));
}
final int width = Math.round(layout.getWidth());
final int height = Math.round(layout.getHeight());
// Add the node's information to our string
sb.append(id).append(' ').append(x).append(' ').append(y).append(' ').append(width).append(' ').append(height).append(';');
}
return sb.toString();
}
/**
* This method iterates through all edges and creates a semicolon separated String containing bend points of all edges.
*
* @return The string containing the bend points.
*/
public String getBendPoints() {
final StringBuilder sb = new StringBuilder();
int e;
final int len = this.edges.length;
final int el = 4;
// Iterate through all edges.
for (int i = 0; i < len; i++) {
e = 0;
final KEdge edge = (KEdge) this.edges[i][e];
final KEdgeLayout layout = edge.getData(KEdgeLayout.class);
final EList<KPoint> bendPoints = layout.getBendPoints();
// add IDs and portIndices
while (++e < el) {
sb.append(this.edges[i][e].toString());
sb.append(" ");
}
sb.append(this.edges[i][4].toString());
// iterate bend points
final int bl = bendPoints.size();
KPoint point;
if (bl > 0) {
point = bendPoints.get(0);
sb.append(' ');
sb.append(Math.round(point.getX()));
sb.append(' ');
sb.append(Math.round(point.getY()));
for (int b = 1; b < bl; b++) {
sb.append(' ');
point = bendPoints.get(b);
sb.append(Math.round(point.getX()));
sb.append(' ');
sb.append(Math.round(point.getY()));
}
}
sb.append(';');
}
return sb.toString();
}
/**
......@@ -136,56 +238,37 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
* The scale factor of the graph.
* @param nodeInfo
* Information about the nodes: isItCustom?, width, height, parent, portInformation
* @param layoutInformation
* The necessary information about the graph.
*
* @throws NumberFormatException
* The nodeInfo should mostly be space separated numbers. If it is however invalid, this
* Exception will be thrown
* The nodeInfo should mostly be space separated numbers. If it is however invalid, this Exception will be thrown
*/
private static void addNodes(final int scale, final String[] nodeInfo, final LayoutInformation layoutInformation) throws NumberFormatException {
// define node HashMap port list
final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts();
List<Object> nodeAndPortList;
private void addNodes(final int scale, final String[] nodeInfo) throws NumberFormatException {
// retrieve size modifier
final int dimHalf = scale;
final int dim = dimHalf * 2;
// loop variables //
String[] nodeProps;
KNode node;
String parentId;
KNode parent;
KPort port;
KShapeLayout layout;
boolean isNodeFamily;
int width;
int height;
int portCount;
int portType;
int portX;
int portY;
int i;
int n;
int p;
int lp;
final int l = nodeInfo.length;
// nodeID : KNode, ParentID
// -- 1. Define nodes by the properties, given in the string --
for (n = 0; n < l; n++) {
for (int n = 0; n < l; n++) {
// i is our property array-pointer
i = 0;
nodeProps = nodeInfo[n].split(" ");
int i = 0;
final String[] nodeProps = nodeInfo[n].split(" ");
// add entry to map
nodeAndPortList = new ArrayList<Object>();
nodesAndPorts.put(nodeProps[i++], nodeAndPortList);
final List<Object> nodeAndPortList = new ArrayList<Object>();
this.children.put(nodeProps[i++], nodeAndPortList);
// create empty node
node = KimlUtil.createInitializedNode();
nodeAndPortList.add(node);
......@@ -194,16 +277,16 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
parentId = nodeProps[i++];
if ("-1".equals(parentId)) {
parentId = "";
node.setParent(layoutInformation.getGraph());
node.setParent(this.getGraph());
}
nodeAndPortList.add(parentId);
// get width and height
width = Integer.parseInt(nodeProps[i++]);
height = Integer.parseInt(nodeProps[i++]);
final int width = Integer.parseInt(nodeProps[i++]);
final int height = Integer.parseInt(nodeProps[i++]);
// get Custom Node tag
isNodeFamily = "f".equals(nodeProps[i++]);
final boolean isNodeFamily = "f".equals(nodeProps[i++]);
// set width and height of KNode
layout = node.getData(KShapeLayout.class);
......@@ -215,19 +298,19 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
// nodeFamily size is fixed
layout.setProperty(LayoutOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
portX = -dimHalf;
int portX = -dimHalf;
// add Ports
for (portType = 0; portType < 3; portType++) {
for (int portType = 0; portType < 3; portType++) {
// determine port x-position
if (portType == 1) {
portX = width - dimHalf;
}
portCount = Integer.parseInt(nodeProps[i++]);
portY = Integer.parseInt(nodeProps[i++]);
final int portCount = Integer.parseInt(nodeProps[i++]);
int portY = Integer.parseInt(nodeProps[i++]);
for (p = 0, lp = portCount; p < lp; p++) {
for (int p = 0; p < portCount; p++) {
// create port
port = KimlUtil.createInitializedPort();
......@@ -250,17 +333,14 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
}
// -- 2. resolve stored parentIDs to actual parents
final Iterator<Entry<String, List<Object>>> it = nodesAndPorts.entrySet().iterator();
while (it.hasNext()) {
nodeAndPortList = (List<Object>) ((Entry) it.next()).getValue();
for (final List<Object> nodeAndPortList : this.children.values()) {
// get KNode and its parentID
node = (KNode) nodeAndPortList.get(0);
parentId = nodeAndPortList.get(1).toString();
// set other KNode as parent
if (!parentId.isEmpty()) {
parent = (KNode) nodesAndPorts.get(parentId).get(0);
parent = (KNode) this.children.get(parentId).get(0);
node.setParent(parent);
}
}
......@@ -279,70 +359,54 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
*
* @param edgeInfo
* The single elements for the edges.
* @param layoutInformation
* The necessary information about the graph.
* @throws UninitializedGraphException
* If the graph has not yet been initialized.
*
* @throws NumberFormatException
* If the given graph is invalid.
*/
private static void addEdges(final String[] edgeInfo, final LayoutInformation layoutInformation) throws NumberFormatException {
final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts();
// set up loop variables
String[] edgeProps;
KEdge edge;
private void addEdges(final String[] edgeInfo) throws NumberFormatException {
// Set up some loop variables
String id;
boolean hasSourcePort;
Object[] edgeList;
KNode sourceNode;
int sourcePortIndex;
KPort sourcePort = null;
List<Object> sourceList;
int targetPortIndex;
KPort targetPort;
List<Object> targetList;
int ea = 0;
int p;
int epl;
// read from String
for (final String element : edgeInfo) {
// get edge info of a single source
edgeList = layoutInformation.getEdges()[ea++];
edgeProps = element.split(" ");
final Object[] edgeList = this.edges[ea++];
final String[] edgeProps = element.split(" ");
p = 0;
// get source index and port
id = edgeProps[p++];
sourceList = nodesAndPorts.get(id);
sourceNode = (KNode) sourceList.get(0);
final List<Object> sourceList = this.children.get(id);
final KNode sourceNode = (KNode) sourceList.get(0);
sourcePortIndex = Integer.parseInt(edgeProps[p++]);
edgeList[2] = sourcePortIndex;
hasSourcePort = ++sourcePortIndex != 0;
final boolean hasSourcePort = ++sourcePortIndex != 0;
final KPort sourcePort;
if (hasSourcePort) {
sourcePort = (KPort) sourceList.get(++sourcePortIndex);
} else {
sourcePort = null;
}
// get target ports
epl = edgeProps.length;
final int epl = edgeProps.length;
while (p < epl) {
// init edge
edge = KimlUtil.createInitializedEdge();
final KEdge edge = KimlUtil.createInitializedEdge();
edgeList[0] = edge;
edgeList[1] = id;
// get target index and port
id = edgeProps[p++];
edgeList[3] = id;
targetList = nodesAndPorts.get(id);
final List<Object> targetList = this.children.get(id);
// select connected nodes
edge.setSource(sourceNode);
......@@ -352,7 +416,7 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
edgeList[4] = targetPortIndex;
if (++targetPortIndex != 0) {
targetPort = (KPort) targetList.get(++targetPortIndex);
final KPort targetPort = (KPort) targetList.get(++targetPortIndex);
// set target port of edge
edge.setTargetPort(targetPort);
......@@ -377,180 +441,5 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
return arr;
}
}
/**
* Reads the (layouted) positions of a constructed KGraph and writes them as integers to a string, seperating each number with a space.
*
* @param layoutInformation
* The object containing the necessary information about the graph.
*
* @return The constructed string.
*/
private static String getPositions(final LayoutInformation layoutInformation) {
final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts();
final StringBuilder sb = new StringBuilder();
// Run through all available entries
for (final Map.Entry<String, List<Object>> entry : nodesAndPorts.entrySet()) {
final String id = entry.getKey();
final List<Object> nodeAndPortList = entry.getValue();
final KShapeLayout layout = ((KNode) nodeAndPortList.get(0)).getData(KShapeLayout.class);
// Get the position of the node
final int posX = Math.round(layout.getXpos() + (layout.getWidth() / 2));
final int posY;
// HotFix: wrong nodeFamily position: needs to be half the height lower
if (nodeAndPortList.size() > 2) {
posY = Math.round(layout.getYpos() + (layout.getHeight()));
} else {
posY = Math.round(layout.getYpos() + (layout.getHeight() / 2));
}
// Get the size of the node
final int width = Math.round(layout.getWidth());
final int height = Math.round(layout.getHeight());
// Put everything into the string
sb.append(id);
sb.append(" ");
sb.append(posX);
sb.append(" ");
sb.append(posY);
sb.append(" ");
sb.append(width);
sb.append(" ");
sb.append(height);
sb.append(";");
}
return sb.toString();
}
/**
* This method iterates through all edges of the given object and creates a semicolon separated String containing bend points of all edges.
*
* @param layoutInformation
* The object containing the information about the graph and the layout.
* @return The string containing the bend points.
*/
private static String getBendPoints(final LayoutInformation layoutInformation) {
final StringBuilder sb = new StringBuilder();
final Object[][] edges = layoutInformation.getEdges();
KEdge edge;
int e;
final int l = edges.length;
final int el = 4;
// iterate edges
for (int i = 0; i < l; i++) {
e = 0;
edge = (KEdge) edges[i][e];
final KEdgeLayout layout = edge.getData(KEdgeLayout.class);
final EList<KPoint> bendPoints = layout.getBendPoints();
// add IDs and portIndices
while (++e < el) {
sb.append(edges[i][e].toString());
sb.append(" ");
}
sb.append(edges[i][4].toString());
// iterate bend points
final int bl = bendPoints.size();
KPoint point;
if (bl > 0) {
point = bendPoints.get(0);
sb.append(" ");
sb.append(Math.round(point.getX()));
sb.append(" ");
sb.append(Math.round(point.getY()));
for (int b = 1; b < bl; b++) {
sb.append(" ");
point = bendPoints.get(b);
sb.append(Math.round(point.getX()));
sb.append(" ");
sb.append(Math.round(point.getY()));
}
}
sb.append(";");
}
return sb.toString();
}
/**
* A container for the layout information which will be assembled during the layout process.
*
* @author Nils Christian Ehmke
*/
private static class LayoutInformation {
private final KNode graph;
/**
* An array containing the child node and the ports from left to right.
*/
private final Map<String, List<Object>> children;
/**
* An array containing edges. This way we can return edge information in the same order.
*/
private final Object[][] edges;
/**
* Creates a new instance of this class.
*
* @param graph
* The graph itself.
* @param children
* The child notes and the ports.
* @param edges
* The edges of the graph.
*/
public LayoutInformation(final KNode graph, final Map<String, List<Object>> children, final Object[][] edges) { // NOPMD (array)
this.graph = graph;
this.children = children;
this.edges = edges;
// set graph layout options
final KShapeLayout layout = graph.getData(KShapeLayout.class);
// layout.setProperty(LayoutOptions.LAYOUT_HIERARCHY, true);
layout.setProperty(LayoutOptions.EDGE_ROUTING, EdgeRouting.ORTHOGONAL);
}
/**
* Getter for the property {@link LayoutInformation#graph}.
*
* @return The current value of the property.
*/
public KNode getGraph() {
return this.graph;
}
/**
* Getter for the property {@link LayoutInformation#children}.
*
* @return The current value of the property.
*/
public Map<String, List<Object>> getNodesAndPorts() {
return this.children;
}
/**
* Getter for the property {@link LayoutInformation#edges}.
*
* @return The current value of the property.
*/
public Object[][] getEdges() {
return this.edges; // NOPMD (array)
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment