Kolja Strohm 7 лет назад
Родитель
Сommit
eb64ad5f1b

+ 2 - 1
.gitignore

@@ -3,4 +3,5 @@ bin
 out
 auxil
 svg-inkscape
-*.synctex*
+*.synctex*
+*.vpp.bak*

+ 0 - 0
big.graph → big.json


+ 78 - 36
doc/chapter/2architecture.tex

@@ -18,7 +18,15 @@ The structure is as follows:
     \item An edge has the attributes that are displayed in table~\ref{table:edge-attributes}.
 \end{itemize}
 For parsing the JSON file the JSON-java library~\cite{leary_json-java:_2018} is used.
+The classes for reading and writing those JSON files are displayed in figure~\ref{fig:io}.
+The internal representation of graphs is further explained in the section~\ref{sec:model}.
 
+\begin{figure}[tp]
+    \centering
+    \includegraphics[width=\linewidth, trim={0 20cm 0 0}]{img/IO.pdf}
+    \caption{Class diagram of the \enquote{IO} package, containing utilities for reading and writing graphs.}
+    \label{fig:io}
+\end{figure}
 
 \centering
 \begin{longtable}{|p{1.8cm}|p{2cm}|p{1.8cm}|p{8.5cm}|}
@@ -31,10 +39,12 @@ For parsing the JSON file the JSON-java library~\cite{leary_json-java:_2018} is
     The node can be higher if it contains other nodes that need more space. \\\hline
     layers & list of lists of nodes & yes & The layers of nodes inside this node (Hierarchy). \\\hline
     edges & list of edges & yes & The edges between nodes whose parent node is this node. \\\hline
-\caption{Node Attributes}
-\label{table:node-attributes}
+    \caption{Node Attributes}
+    \label{table:node-attributes}
 \end{longtable}
 
+\newpage
+
 \begin{longtable}{|p{1.8cm}|p{2cm}|p{1.8cm}|p{8.5cm}|}
     \hline
     Attribute & Type & Optional & Explanation \\\hline\hline
@@ -42,8 +52,8 @@ For parsing the JSON file the JSON-java library~\cite{leary_json-java:_2018} is
     Must be a node with the same parent node as the node specified by the \enquote{target} attribute. \\\hline
     target & string & no & The name of the target of this edge.
     Must be a node with the same parent node as the node specified by the \enquote{source} attribute. \\\hline
-\caption{Edge Attributes}
-\label{table:edge-attributes}
+    \caption{Edge Attributes}
+    \label{table:edge-attributes}
 \end{longtable}
 \raggedright
 
@@ -55,40 +65,72 @@ For parsing the JSON file the JSON-java library~\cite{leary_json-java:_2018} is
 %\end{figure}
 
 \begin{figure}
-    \begin{lstlisting}[language=json,emph={}]
-    {
-       "layers":[
-          [
-             {
-                "name":"n2",
-                "width":10,
-                "height":10
-             },
-             {
-                "name":"n1",
-                "width":10,
-                "height":10,
-                "layers":[
-                   [
-                      {
-                         "name":"n2",
-                         "width":10,
-                         "height":10
-                      }
-                   ]
-                ]
-             }
-          ]
-       ],
-       "name":"n0"
-    }
-    \end{lstlisting}
+    \begin{lstinputlisting}[language=json,emph={}]{img/graph.json}
+    \end{lstinputlisting}
     \caption[Example Input File]{Example Input file that is understood by \appname.}
     \label{fig:json-example}
 \end{figure}
 
-\section{Internal graph representation}\label{sec:internalGraphRepresentation}
-\TODO{some class diagram}
+\section{Internal graph representation, \enquote{Model}}\label{sec:model}
+One feature that is important to us, is to be able to work with hierarchical graphs (cf.\ chapter~\ref{ch:progress}).
+Therefore a node not only has edges to other nodes, but also it can contain other nodes and edges.
+So far this is similar to what we described in section~\ref{sec:inputFileFormat}.
+Additionally, there are multiple attributes that are used during the computation or as output variables.
+\begin{itemize}
+    \item The attributes \enquote{shift},  \enquote{sink},  \enquote{root} and  \enquote{align} correspond to the variables used by Brandes and Köpf~\cite{brandes_fast_2001}.
+    They are summarized in table~\ref{table:bk-variables}.
+    \item The \enquote{parent} of a node is the node that contains it in the hierarchy.
+    \item The attributes $x$ and $y$ are the coordinates of the node relative to its parent node.
+\end{itemize}
+Similarly, edges have additional attributes:
+\begin{itemize}
+    \item \enquote{dummy} specifies whether they are dummy edges.
+    \item \enquote{conflicted} corresponds to the variable used by Brandes and Köpf~\cite{brandes_fast_2001} and indicates that this edge won't be drawn vertically.
+    \item \enquote{bindPoints} is a list of bend points for the edge.
+\end{itemize}
+
+A class diagram of the package \enquote{Model} is displayed in figure~\ref{fig:model}.
+
+\begin{figure}[tp]
+    \centering
+    \includegraphics[width=\linewidth, trim={0 6cm 0 0}]{img/Model.pdf}
+    \caption{Class diagram of the \enquote{Model} package.}
+    \label{fig:model}
+\end{figure}
+
+\begin{longtable}{|p{2.8cm}|p{10cm}|}
+    \hline
+    Attribute & Explanation \\\hline\hline
+    root & The root node of the block of this node.
+    Unique for all nodes in the same block. \\\hline
+    sink & The topmost sink in the block graph that can be reached from the block that this node belongs to.
+    Only used for nodes that are the root of a block.
+    Unique for all nodes in the same class. \\\hline
+    shift & The shift of the class that this node belongs to.
+    Only used for nodes that are a sink of a class. \\\hline
+    \caption{Variables also used by Brandes and Köpf~\cite{brandes_fast_2001}}
+    \label{table:bk-variables}
+\end{longtable}
+
+\section{The actual algorithm}\label{sec:theActualAlgorithm}
+This section assumes that the reader is familiar with the node placement algorithm by Brandes and Köpf~\cite{brandes_fast_2001}.
+
+A \enquote{stage} of the algorithm, interface \enquote{AlgorithmStage}, is an interval during which each step of the algorithm is performed in a similar way.
+Each time such a step is performed it returns whether the stage is already finished.
+For example, a forward step in the stage of calculating one extremal layout, class \enquote{ExtremalLayoutCalc}, consists of either a step of calculating the blocks, class \enquote{BlockCalc}, or a step of compacting the layout, class \enquote{Compaction}.
+All the stages are displayed in class diagram~\ref{fig:animated}.
+
+To be able to undo a step each stage needs to implement methods for both forward and backward steps.
+
+\begin{figure}[tp]
+    \centering
+    \includegraphics[width=\linewidth, trim={0 9cm 0 0}]{img/Algorithms_Animated.pdf}
+    \caption{Class diagram of the package \enquote{Algorithms.Animated}.}
+    \label{fig:animated}
+\end{figure}
+
+\section{View}\label{sec:view}
+This section only covers the software architecture regarding the views.
+For an explanation of what is actually displayed, see chapter~\ref{ch:ui}
 
-\section{TODO: More Class Diagrams}\label{sec:classDiagrams}
-\TODO{maybe even into appendix}
+\TODO{Kolja ausfragen}

+ 7 - 0
doc/chapter/3ui.tex

@@ -0,0 +1,7 @@
+Note that since the application is still under construction, so not all screenshots may be up to date.
+
+\section{Graphical presentation of the running algorithm}\label{sec:graphicalPresentationOfTheRunningAlgorithm}
+\TODO{under construction}
+
+\section{User interface}\label{sec:userInterface}
+\TODO{under construction}

+ 5 - 3
doc/chapter/3progress.tex → doc/chapter/4progress.tex

@@ -21,11 +21,13 @@ The following features are either planned (\planned), under construction (\progr
         \item[\progress] Drawing the four extremal layouts and the combined layout separately.
         \item[\planned] Drawing the edges of the block graph (in a different color than other edges).
     \end{itemize}
-    \item[\done] Running the algorithm step by step manually (by pushing a button labeled \enquote{Step}).
+    \item[\done] Running the algorithm step by step manually.
     \item[\progress] Running the algorithm step by step with configurable delay.
     \item[\planned] Using debugger-like commands such as \enquote{step into}, \enquote{step over}, \enquote{step out}.
+    \item[\planned] Adding buttons and other graphical elements to support the user interface (low priority).
+    Currently there is only keyboard input (cf.\ section~\ref{sec:userInterface}).
     \item[\done] Working with hierarchical graphs.
     \item[\done] Scaling the display with the (adjustable) window size.
-    \item[\planned] Creating ElkNode~\cite{noauthor_elk:_2018} objects from LayeredNode (\ref{sec:internalGraphRepresentation}) objects
-    \item[\planned] Creating LayeredNode (\ref{sec:internalGraphRepresentation}) objects from ElkNode~\cite{noauthor_elk:_2018} objects (low priority)
+    \item[\planned] Creating ElkNode~\cite{noauthor_elk:_2018} objects from LayeredNode (\ref{sec:model}) objects
+    \item[\planned] Creating LayeredNode (\ref{sec:model}) objects from ElkNode~\cite{noauthor_elk:_2018} objects (low priority)
 \end{itemize}

+ 0 - 0
doc/chapter/4retrospection.tex → doc/chapter/5retrospection.tex


+ 5 - 4
doc/doc.tex

@@ -245,13 +245,14 @@ frame=tb}
     \chapter{Architecture}\label{ch:architecture}
     \input{chapter/2architecture}
 
-    \chapter{Current Progress}\label{ch:progress}
-    \input{chapter/3progress}
+    \chapter{UI and visuals}\label{ch:ui}
+    \input{chapter/3ui}
 
-    \TODO{UI and visuals chapter}
+    \chapter{Current Progress}\label{ch:progress}
+    \input{chapter/4progress}
 
     \chapter{Retrospection}
-    \input{chapter/4retrospection}
+    \input{chapter/5retrospection}
 
     \appendix
     \chapter{Appendix}\label{ch:appendix}

BIN
doc/img/Algorithms_Animated.pdf


BIN
doc/img/IO.pdf


BIN
doc/img/Model.pdf


BIN
doc/img/View.pdf


+ 26 - 0
doc/img/graph.json

@@ -0,0 +1,26 @@
+{
+   "layers":[
+      [
+         {
+            "name":"n2",
+            "width":10,
+            "height":10
+         },
+         {
+            "name":"n1",
+            "width":10,
+            "height":10,
+            "layers":[
+               [
+                  {
+                     "name":"n2",
+                     "width":10,
+                     "height":10
+                  }
+               ]
+            ]
+         }
+      ]
+   ],
+   "name":"n0"
+}

BIN
doc/img/logo.jpg


BIN
doc/vpp/animation.animated.vpp


BIN
doc/vpp/io.vpp


BIN
doc/vpp/model.vpp


BIN
doc/vpp/view.vpp


+ 0 - 0
save.graph → save.json


+ 0 - 1
save_err1.graph

@@ -1 +0,0 @@
-{"layers":[[{"layers":[],"edges":[],"name":"0"},{"layers":[],"edges":[],"name":"1"},{"layers":[],"edges":[],"name":"2"},{"layers":[],"edges":[],"name":"3"},{"layers":[],"edges":[],"name":"4"}],[{"layers":[],"edges":[],"name":"5"},{"layers":[],"edges":[],"name":"6"},{"layers":[],"edges":[],"name":"7"},{"layers":[],"edges":[],"name":"8"},{"layers":[],"edges":[],"name":"9"}],[{"layers":[],"edges":[],"name":"10"},{"layers":[],"edges":[],"name":"11"},{"layers":[],"edges":[],"name":"12"},{"layers":[],"edges":[],"name":"13"},{"layers":[],"edges":[],"name":"14"}],[{"layers":[],"edges":[],"name":"15"},{"layers":[],"edges":[],"name":"16"},{"layers":[],"edges":[],"name":"17"},{"layers":[],"edges":[],"name":"18"},{"layers":[],"edges":[],"name":"19"}],[{"layers":[],"edges":[],"name":"20"},{"layers":[],"edges":[],"name":"21"},{"layers":[],"edges":[],"name":"22"},{"layers":[],"edges":[],"name":"23"},{"layers":[],"edges":[],"name":"24"}]],"edges":[{"source":"0","target":"7"},{"source":"1","target":"7"},{"source":"2","target":"9"},{"source":"7","target":"10"},{"source":"7","target":"13"},{"source":"13","target":"17"},{"source":"12","target":"16"},{"source":"19","target":"23"},{"source":"19","target":"24"},{"source":"15","target":"20"},{"source":"18","target":"22"},{"source":"17","target":"21"}]}

+ 24 - 0
save_err1.json

@@ -0,0 +1,24 @@
+{
+	"layers":[
+		[
+			{"name":"1"},
+			{"name":"2"}
+		],
+		[
+			{"name":"3"},
+			{"name":"4"},
+			{"name":"5"}
+		],
+		[
+			{"name":"6"},
+			{"name":"7"}
+		]
+	],
+	"edges":[
+		{"source":"1","target":"5"},
+		{"source":"2","target":"5"},
+		{"source":"3","target":"7"},
+		{"source":"5","target":"7"},
+		{"source":"4","target":"7"}
+	]
+}

+ 4 - 4
src/Algorithms/Animated/BK/BlockCalc.java

@@ -20,8 +20,8 @@ public class BlockCalc implements AlgorithmStage {
 	private int nodeIndex;
 	private int r;
 	private LayeredGraphNode graph;
-	private ArrayList< ArrayList< BKNodePlacement > > subgraphAlgs;
-	private ArrayList< BackwardAction > backwards;
+	private ArrayList< ArrayList< ExtremalLayoutCalc > > subgraphAlgs;
+	private ArrayList< BackwardAction > backwards; // TODO: evtl richtigen "Stack" benutzen
 	private LayoutType layout;
 	int step;
 	
@@ -36,7 +36,7 @@ public class BlockCalc implements AlgorithmStage {
 		subgraphAlgs = new ArrayList<>();
 		for( ArrayList<LayeredGraphNode> l : graph.getContainedLayers() )
 		{
-			ArrayList< BKNodePlacement > algs = new ArrayList<>();
+			ArrayList< ExtremalLayoutCalc > algs = new ArrayList<>();
 			for( int i = 0; i < l.size(); i++ )
 				algs.add( null );
 			subgraphAlgs.add( algs );
@@ -78,7 +78,7 @@ public class BlockCalc implements AlgorithmStage {
 		if( current.getContainedNodes().size() > 0 )
 		{
 			if( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ) == null )
-				subgraphAlgs.get( calcLayerIndex() ).set( calcNodeIndex( nodeIndex ), new BKNodePlacement( null, current ) );
+				subgraphAlgs.get( calcLayerIndex() ).set( calcNodeIndex( nodeIndex ), new ExtremalLayoutCalc( layout, current ) );
 			if( subgraphAlgs.get( calcLayerIndex() ).get( calcNodeIndex( nodeIndex ) ).forwardStep() == StageStatus.UNFINISHED )
 				return StageStatus.UNFINISHED;
 		}

+ 17 - 8
src/Algorithms/Animated/BK/Compaction.java

@@ -1,6 +1,7 @@
 package Algorithms.Animated.BK;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 import Algorithms.Animated.AlgorithmStage;
 import Algorithms.Animated.BackwardAction;
@@ -54,9 +55,13 @@ public class Compaction implements AlgorithmStage{
 		return max;
 	}
 	
+	@SuppressWarnings("unchecked")
 	private LayeredGraphNode getNodeFromIndex( int index )
 	{
-	    for( ArrayList< LayeredGraphNode > l : graph.getContainedLayers() )
+		ArrayList< ArrayList< LayeredGraphNode > > layers = (ArrayList<ArrayList<LayeredGraphNode>>) graph.getContainedLayers().clone();
+        if( layout == LayoutType.BOTTOM_TOP_LEFT || layout == LayoutType.BOTTOM_TOP_RIGHT )
+        	Collections.reverse( layers );
+	    for( ArrayList< LayeredGraphNode > l : layers )
 	    {
 	        if( index >= l.size() )
 	            index -= l.size();
@@ -106,7 +111,7 @@ public class Compaction implements AlgorithmStage{
 					f.v.setX( 0, true, layout );
 					f.v.setSelected( layout ); // zeige knoten als aktiven knoten an
 					f.w = f.v;
-                    System.out.println( "call place_block( " + f.v + " )" );
+                    System.out.println( "call place_block( " + f.v.getName() + " )" );
 					stack.add( 0, f );
 					
 					// die "undo"-action
@@ -138,7 +143,7 @@ public class Compaction implements AlgorithmStage{
 							nsf.v.setX( 0, true, layout );
 							nsf.v.setSelected( layout ); // zeige knoten als aktiven knoten an
 							nsf.w = nsf.v;
-		                    System.out.println( "call place_block( " + nsf.v + " )" );
+		                    System.out.println( "call place_block( " + nsf.v.getName() + " )" );
 							stack.add( 0, nsf );
 		                    
 		                    // die "undo"-action
@@ -165,7 +170,7 @@ public class Compaction implements AlgorithmStage{
 						sf.w = sf.w.getAlignedTo( layout );
 						if( sf.w == sf.v ) // schleifenabbruchbedingung
 						{ //abbrechen, placeblock beendet
-                            System.out.println( "return place_block( " + sf.v + " )" );
+                            System.out.println( "return place_block( " + sf.v.getName() + " )" );
 							stack.remove( 0 );
 							actions.add( 0, ()-> {
 								stack.add( 0, sf );
@@ -198,9 +203,13 @@ public class Compaction implements AlgorithmStage{
                         sf.v.setSink( sf.u.getSink( layout ), layout ); // sink[v] := sink[u]
 
 					if( sf.v.getSink( layout ) != sf.u.getSink( layout ) ) // sink[v] != sink [u]?
+					{
 						sf.u.getSink( layout ).setShift( // shift[sink[u]] =
 						  Math.min( sf.u.getSink( layout ).getShift( layout ),  // min(shift[sink[u]]
 						          sf.v.getX( layout ) - sf.u.getX( layout ) - calcSpacing() ), layout ); // y_v - y_u - s
+						System.out.println( "Set Shift von " + sf.u.getSink( layout ).getName() + " to " + Math.min( sf.u.getSink( layout ).getShift( layout ),  // min(shift[sink[u]]
+						          sf.v.getX( layout ) - sf.u.getX( layout ) - calcSpacing() ) );
+					}
 					else
 					    // y_v = max {y_v, y_u + s}
 						sf.v.setX( Math.max( sf.v.getX( layout ), sf.u.getX( layout ) + calcSpacing() ), true, layout );
@@ -215,7 +224,7 @@ public class Compaction implements AlgorithmStage{
 					
 					if( sf.w == sf.v ) // schleifenabbruchbedingung
 					{ //abbrechen, placeblock beendet  
-					    System.out.println( "return place_block( " + sf.v + " )" );
+					    System.out.println( "return place_block( " + sf.v.getName() + " )" );
 						stack.remove( 0 );
 						actions.add( 0, ()-> {
 							stack.add( 0, sf );
@@ -243,13 +252,13 @@ public class Compaction implements AlgorithmStage{
 		}
 		else if( state == CompactionState.APPLY_SHIFT )
 		{
-			LayeredGraphNode v = graph.getContainedNodes().get( vIndex );
+			LayeredGraphNode v = getNodeFromIndex( vIndex );
 			double oldX = v.getX( layout );
 			boolean oldDef = !v.isXUndefined( layout );
 			v.setSelected( layout );
 			v.setX( v.getRoot( layout ).getX( layout ), true, layout );
-			if( v == v.getRoot( layout ) && v.getRoot( layout ).getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY )
-				v.setX( v.getX( layout ) + v.getRoot( layout ).getSink( layout ).getShift( layout ), true, layout );
+			if( v == v.getRoot( layout ) && v.getSink( layout ).getShift( layout ) < Double.POSITIVE_INFINITY )
+				v.setX( v.getX( layout ) + v.getSink( layout ).getShift( layout ), true, layout );
 			actions.add( 0, ()-> {
 				v.setX( oldX, oldDef, layout );
 				v.setSelected( layout );

+ 3 - 1
src/IO/Reader.java

@@ -36,7 +36,9 @@ public class Reader {
 		String file = "";
 		try {
 			BufferedReader r = new BufferedReader( new FileReader( fileName ) );
-			file += r.readLine();
+			String tmp = null;
+			while( (tmp = r.readLine()) != null )
+				file += tmp;
 			r.close();
 		} catch (IOException e) {
 			e.printStackTrace();

+ 1 - 1
src/Main.java

@@ -15,7 +15,7 @@ public class Main {
 	public static void main(String[] args) {
 		//Reader r = new Reader( "save.graph" );
 		//LayeredGraphNode graph = r.readInputGraph();
-	    RandomGraphGenerator r = new RandomGraphGenerator( 1, 0.5, 2, 2, 2, 2, 5 );
+	    RandomGraphGenerator r = new RandomGraphGenerator( 1, 0.5, 2, 2, 2, 2, 3 );
 	    LayeredGraphNode graph = r.createRandomNode( null, 0 );
 	    SweepCrossingMinimizer cminzer = new SweepCrossingMinimizer();
 	    for( int i = 0; i < 10; i++ )

+ 52 - 1
src/View/MainView.java

@@ -26,6 +26,17 @@ public class MainView {
 	public static JFrame frame;
 	AnimationController controller;
 	
+	private String strToLen( String s, int l )
+	{
+		while( s.length() < l )
+		{
+			s = " " + s + " ";
+		}
+		if( s.length() > l )
+			return s.substring( 0, l );
+		return s;
+	}
+	
 	/**
 	 * Initialize the window and its contents.
 	 * @param graph the graph that is displayed in this window.
@@ -52,7 +63,7 @@ public class MainView {
             public void keyPressed(KeyEvent e) {
                 if( e.getKeyCode() == KeyEvent.VK_S )
                 {
-                    Writer w = new Writer( "save.graph" );
+                    Writer w = new Writer( "save.json" );
                     w.writeOutputGraph( graph );
                 }
                 if( e.getKeyCode() == KeyEvent.VK_LEFT )
@@ -62,6 +73,46 @@ public class MainView {
                 if( e.getKeyCode() == KeyEvent.VK_P )
                 	controller.setContinuous( !controller.isContinuous() );
         		frame.validate();
+        		if( e.getKeyCode() == KeyEvent.VK_D )
+        		{
+        			System.out.println( "Debug Information Table: " );
+        			System.out.println( "_______________________________________________________________________________________________________________________________________________________________________________________________________________________" );
+        			System.out.println( "|" + strToLen( "Top -> Bottom :> Left", 51 ) + "| |" + strToLen( "Top -> Bottom :> Right", 51 ) + "| |" + strToLen( "Bottom -> Top :> Left", 51 ) + "| |" + strToLen( "Bottom -> Top :> Right", 51 ) + "|" );
+        			System.out.println( "|___________________________________________________| |___________________________________________________| |___________________________________________________| |___________________________________________________|" );
+        			System.out.println( "| Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  | | Node | Shift | Sink | Root | Align |  x  |  xDef  |" );
+        			for( LayeredGraphNode n : graph.getContainedNodes() )
+        			{
+        				System.out.println( "|" + strToLen( n.getName(), 6 ) + 
+		        						    "|" + strToLen( n.getShift( LayoutType.TOP_BOTTOM_LEFT ) + "", 7 ) + 
+		        						    "|" + strToLen( n.getSink( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getRoot( LayoutType.TOP_BOTTOM_LEFT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getAlignedTo( LayoutType.TOP_BOTTOM_LEFT ).getName(), 7 ) + 
+		        						    "|" + strToLen( n.getX( LayoutType.TOP_BOTTOM_LEFT ) + "", 5 ) + 
+		        						    "|" + strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_LEFT ) + "", 8 ) + "| " +
+		        						    "|" + strToLen( n.getName(), 6 ) + 
+		        						    "|" + strToLen( n.getShift( LayoutType.TOP_BOTTOM_RIGHT ) + "", 7 ) + 
+		        						    "|" + strToLen( n.getSink( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getRoot( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getAlignedTo( LayoutType.TOP_BOTTOM_RIGHT ).getName(), 7 ) + 
+		        						    "|" + strToLen( n.getX( LayoutType.TOP_BOTTOM_RIGHT ) + "", 5 ) + 
+		        						    "|" + strToLen( !n.isXUndefined( LayoutType.TOP_BOTTOM_RIGHT ) + "", 8 ) + "| " +
+		        						    "|" + strToLen( n.getName(), 6 ) + 
+		        						    "|" + strToLen( n.getShift( LayoutType.BOTTOM_TOP_LEFT ) + "", 7 ) + 
+		        						    "|" + strToLen( n.getSink( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getRoot( LayoutType.BOTTOM_TOP_LEFT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getAlignedTo( LayoutType.BOTTOM_TOP_LEFT ).getName(), 7 ) + 
+		        						    "|" + strToLen( n.getX( LayoutType.BOTTOM_TOP_LEFT ) + "", 5 ) + 
+		        						    "|" + strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_LEFT ) + "", 8 ) + "| " +
+		        						    "|" + strToLen( n.getName(), 6 ) + 
+		        						    "|" + strToLen( n.getShift( LayoutType.BOTTOM_TOP_RIGHT ) + "", 7 ) + 
+		        						    "|" + strToLen( n.getSink( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getRoot( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 6 ) + 
+		        						    "|" + strToLen( n.getAlignedTo( LayoutType.BOTTOM_TOP_RIGHT ).getName(), 7 ) + 
+		        						    "|" + strToLen( n.getX( LayoutType.BOTTOM_TOP_RIGHT ) + "", 5 ) + 
+		        						    "|" + strToLen( !n.isXUndefined( LayoutType.BOTTOM_TOP_RIGHT ) + "", 8 ) + "|");
+        			}
+        			System.out.println( "-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------" );
+        		}
             }
 
             @Override

+ 11 - 4
src/View/NodeView.java

@@ -72,18 +72,25 @@ public class NodeView extends JPanel {
 		g2.setColor( model.getColor( layout ) );
 		g2.setStroke(new BasicStroke(5));
 		if( model.getContainedNodes().size() == 0 )
-			g2.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+		{
+			if( model.getRoot( layout ) == model )
+				g2.fillOval( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+			else
+				g2.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+		}
 		if( model.isSelected( layout ) )
 		{
 			g.setColor( Color.GRAY );
 			g.fillRect( 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
 		}
 		Border linebor = BorderFactory.createLineBorder(model.getColor( layout ), 5);
-		linebor.paintBorder( this, g2, 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
-		if( model.getRoot( layout ).getSink( layout ).getColor( layout ) != model.getColor( layout ) )
+		if( model.getRoot( layout ) != model || model.getContainedNodes().size() != 0  )
+			linebor.paintBorder( this, g2, 0, 0, (int)model.getWidth( layout )-1, (int)model.getHeight( layout )-1 );
+		if( model.getRoot( layout ).getSink( layout ).getColor( layout ) != model.getColor( layout ))
 		{
     		g.setColor( model.getRoot( layout ).getSink( layout ).getColor( layout ) );
-    		g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
+    		if( model.getContainedNodes().size() == 0 )
+    		    g.fillOval( (int)model.getWidth( layout ) / 2 - (int)model.getWidth( layout ) / 3, (int)model.getHeight( layout ) / 2 - (int)model.getHeight( layout ) / 3, (int)model.getWidth( layout ) / 3 * 2, (int)model.getHeight( layout ) / 3 * 2 );
 		}
 	}
 }

+ 0 - 0
test.graph → test.json


+ 0 - 0
test2.graph → test2.json


+ 0 - 0
test3.graph → test3.json


+ 18 - 0
test4.json

@@ -0,0 +1,18 @@
+{
+"layers": [
+	[
+		{"name": "n1","width":40,"height":40},
+		{"name":"n2","width":40,"height":40}
+	],
+	[
+		{"name":"n3","width":40,"height":40},
+		{"name":"n4","width":40,"height":40},
+		{"name":"n0","width":40,"height":40}
+	]
+],
+"edges":[
+	{"source":"n1","target":"n0"},
+	{"source":"n2","target":"n0"}
+],
+"name":"n0"
+}