Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization.Views/3.3/NetworkVisualizationView.cs
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization.Views/3.3/NetworkVisualizationView.cs	(revision 13832)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization.Views/3.3/NetworkVisualizationView.cs	(revision 13833)
@@ -65,4 +65,6 @@
       base.OnContentChanged();
       UpdateContent();
+      if (Content != null)
+        LayoutNodes(Content.Nodes);
       chartControl.Tag = Content;
     }
@@ -132,4 +134,7 @@
       chartControl.SuspendRendering();
       try {
+        foreach (var r in primitiveDict.Values.OfType<NodeRectangle>())
+          r.NetworkItem = null;
+        primitiveDict.Clear();
         chartControl.Chart.Group.Clear();
         DrawNodes(Content.Nodes);
@@ -174,4 +179,52 @@
       }
     }
+
+    private void LayoutNodes(IKeyedItemCollection<string, INode> nodes) {
+      var layout = new Layout();
+      var layoutNodes = new Dictionary<string, Layout.LayoutNode>();
+
+      foreach (var node in nodes) {
+        var nodeRectangle = primitiveDict[node.Name] as NodeRectangle;
+        if (nodeRectangle == null) continue;
+
+        var nodeSize = chartControl.Chart.TransformWorldToPixel(nodeRectangle.Size);
+        Layout.LayoutNode layoutNode;
+        if (!layoutNodes.TryGetValue(node.Name, out layoutNode)) {
+          layoutNodes.Add(node.Name, layoutNode = new Layout.LayoutNode(nodeSize));
+          layout.AddNode(layoutNode);
+        }
+
+        foreach (var port in node.Ports.OfType<IConnectablePort>()) {
+          var connectedPort = port.ConnectedPort as IConnectablePort;
+          if (connectedPort == null) continue;
+
+          var connectedNode = connectedPort.Parent;
+          if (connectedNode == null) continue;
+
+          var connectedRectangle = primitiveDict[connectedNode.Name] as NodeRectangle;
+          if (connectedRectangle == null) continue;
+
+          nodeSize = chartControl.Chart.TransformWorldToPixel(connectedRectangle.Size);
+          if (!layoutNodes.ContainsKey(connectedNode.Name)) {
+            layoutNodes.Add(connectedNode.Name, new Layout.LayoutNode(nodeSize));
+            layout.AddNode(layoutNodes[connectedNode.Name]);
+          }
+
+          layoutNode.AddNode(layoutNodes[connectedNode.Name]);
+        }
+      }
+
+      var bounds = chartControl.GetPictureBounds();
+      bounds.Offset((int)chartControl.Chart.LowerLeft.X, -(int)chartControl.Chart.UpperRight.Y);
+
+      layout.Arrange(bounds);
+
+      foreach (var entry in layoutNodes) {
+        var nodeRectangle = primitiveDict[entry.Key] as NodeRectangle;
+        if (nodeRectangle == null) continue;
+        var rectangleNode = entry.Value;
+        nodeRectangle.Move(rectangleNode.Location - nodeRectangle.Center());
+      }
+    }
     #endregion
   }
Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/HeuristicLab.Networks.Views.NetworkVisualization-3.3.csproj
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/HeuristicLab.Networks.Views.NetworkVisualization-3.3.csproj	(revision 13832)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/HeuristicLab.Networks.Views.NetworkVisualization-3.3.csproj	(revision 13833)
@@ -113,4 +113,5 @@
     <Compile Include="INodeVisualProperties.cs" />
     <Compile Include="IPortVisualProperties.cs" />
+    <Compile Include="Layout.cs" />
     <Compile Include="NodeVisualProperties.cs" />
     <Compile Include="Orientation.cs" />
Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Layout.cs
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Layout.cs	(revision 13833)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Layout.cs	(revision 13833)
@@ -0,0 +1,225 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+
+namespace HeuristicLab.Networks.Views.NetworkVisualization {
+  public class Layout {
+    private const double RAD_TO_DEG = 180 / Math.PI;
+    private const double DEG_TO_RAD = 1 / RAD_TO_DEG;
+
+    private const double REPULSION_CONSTANT = 10000.0;
+    private const double ATTRACTION_CONSTANT = 0.1;
+    private const double EQUILIBRIUM = 15;
+
+    private readonly IList<Node> nodes = new List<Node>();
+
+    public bool AddNode(Node node) {
+      if (node == null) throw new ArgumentNullException("node");
+      if (nodes.Contains(node)) return false;
+
+      nodes.Add(node);
+      foreach (var c in node.Nodes) AddNode(c);
+      return true;
+    }
+
+    public void Arrange(double damping = 0.5, double springLength = 100, int maxIterations = 500, bool deterministic = true) {
+      var random = deterministic ? new Random(0) : new Random();
+
+      var nodeMechanics = new NodeMechanics[nodes.Count];
+      for (int i = 0; i < nodes.Count; i++) {
+        nodeMechanics[i] = new NodeMechanics(nodes[i], new Vector(), Point.Empty);
+        nodeMechanics[i].Node.Location = new Point(random.Next(-50, 50), random.Next(-50, 50));
+      }
+
+      for (int i = 0, eqCount = 0; i < maxIterations && eqCount <= EQUILIBRIUM; i++) {
+        double totalDisplacement = 0.0;
+
+        foreach (var current in nodeMechanics) {
+          var node = current.Node;
+          var currentPosition = new Vector(CalculateDistance(Point.Empty, node.Location), CalculateBearingAngle(Point.Empty, node.Location));
+          var netForce = new Vector();
+
+          foreach (var n in nodes)
+            if (n != node)
+              netForce += CalculateRepulsionForce(node, n);
+
+          foreach (var n in node.Nodes)
+            netForce += CalculateAttractionForce(node, n, springLength);
+
+          foreach (var n in nodes)
+            if (n.Nodes.Contains(node))
+              netForce += CalculateAttractionForce(node, n, springLength);
+
+          current.Velocity = (current.Velocity + netForce) * damping;
+          current.NextPosition = (currentPosition + current.Velocity).ToPoint();
+        }
+
+        foreach (var current in nodeMechanics) {
+          totalDisplacement += CalculateDistance(current.Node.Location, current.NextPosition);
+          current.Node.Location = current.NextPosition;
+        }
+
+        if (totalDisplacement < 10) eqCount++;
+      }
+    }
+
+    public void Arrange(Rectangle bounds, double damping = 0.5, double springLength = 100.0, int maxIterations = 500, bool deterministic = true) {
+      Arrange(damping, 200, maxIterations, deterministic);
+
+      var logicalBounds = GetLogicalBounds();
+      var center = new Point(logicalBounds.X + logicalBounds.Width / 2, logicalBounds.Y + logicalBounds.Height / 2);
+      int maxWidth = 0, maxHeight = 0;
+      foreach (var node in nodes) {
+        node.Location -= (Size)center;
+        if (node.Size.Width > maxWidth) maxWidth = node.Size.Width;
+        if (node.Size.Height > maxHeight) maxHeight = node.Size.Height;
+      }
+
+      bounds = new Rectangle(bounds.X + maxWidth / 2, bounds.Y + maxHeight / 2, bounds.Width - maxWidth, bounds.Height - maxHeight);
+      double scale = Math.Min((double)bounds.Width / logicalBounds.Width, (double)bounds.Height / logicalBounds.Height);
+      foreach (var node in nodes)
+        node.Location = ScalePoint(node.Location, scale);
+
+      logicalBounds = GetLogicalBounds();
+      center = new Point(logicalBounds.X + logicalBounds.Width / 2, logicalBounds.Y + logicalBounds.Height / 2);
+      center.Offset(-(bounds.X + bounds.Width / 2), bounds.Y + bounds.Height / 2);
+      foreach (var node in nodes)
+        node.Location -= (Size)center;
+    }
+
+    #region Forces
+    private Vector CalculateRepulsionForce(Node a, Node b) {
+      double r = Math.Max(CalculateDistance(a.Location, b.Location), 1.0);
+      double force = -(REPULSION_CONSTANT / (r * r));
+      double angle = CalculateBearingAngle(a.Location, b.Location);
+      return new Vector(force, angle);
+    }
+
+    private Vector CalculateAttractionForce(Node a, Node b, double springLength) {
+      double r = Math.Max(CalculateDistance(a.Location, b.Location), 1.0);
+      double force = ATTRACTION_CONSTANT * Math.Max(r - springLength, 0.0);
+      double angle = CalculateBearingAngle(a.Location, b.Location);
+      return new Vector(force, angle);
+    }
+    #endregion
+
+    #region Helpers
+    private static double CalculateDistance(Point a, Point b) {
+      double dX = a.X - b.X;
+      double dY = a.Y - b.Y;
+      return Math.Sqrt(dX * dX + dY * dY);
+    }
+
+    private static double CalculateBearingAngle(Point a, Point b) {
+      double dX = b.X - a.X;
+      double dY = b.Y - a.Y;
+      double angle = Math.Atan2(dY, dX) * RAD_TO_DEG;
+      return angle;
+    }
+
+    private static Point ScalePoint(Point p, double scalar) {
+      return new Point((int)Math.Round(p.X * scalar), (int)Math.Round(p.Y * scalar));
+    }
+
+    private Rectangle GetLogicalBounds() {
+      int minX = int.MaxValue, maxX = int.MinValue,
+          minY = int.MaxValue, maxY = int.MinValue;
+      foreach (var node in nodes) {
+        if (node.Location.X < minX) minX = node.Location.X;
+        if (node.Location.X > maxX) maxX = node.Location.X;
+        if (node.Location.Y < minY) minY = node.Location.Y;
+        if (node.Location.Y > maxY) maxY = node.Location.Y;
+      }
+
+      return Rectangle.FromLTRB(minX, minY, maxX, maxY);
+    }
+    #endregion
+
+    #region Vector
+    private struct Vector {
+      public double X { get; private set; }
+      public double Y { get; private set; }
+
+      public Vector(double magnitude, double direction) {
+        X = magnitude * Math.Cos(direction * DEG_TO_RAD);
+        Y = magnitude * Math.Sin(direction * DEG_TO_RAD);
+      }
+
+      public Point ToPoint() {
+        return new Point((int)Math.Round(X), (int)Math.Round(Y));
+      }
+
+      public static Vector operator +(Vector a, Vector b) {
+        return new Vector { X = a.X + b.X, Y = a.Y + b.Y };
+      }
+
+      public static Vector operator *(Vector v, double d) {
+        return new Vector { X = v.X * d, Y = v.Y * d };
+      }
+    }
+    #endregion
+
+    #region Nodes
+    public abstract class Node {
+      public Point Location { get; set; }
+      public abstract Size Size { get; }
+
+      private readonly List<Node> nodes = new List<Node>();
+      public IEnumerable<Node> Nodes { get { return nodes; } }
+
+      public bool AddNode(Node node) {
+        if (node == null) throw new ArgumentNullException("node");
+        if (node == this || nodes.Contains(node)) return false;
+
+        nodes.Add(node);
+        return true;
+      }
+    }
+
+    public class LayoutNode : Node {
+      private Size size;
+      public override Size Size { get { return size; } }
+
+      public LayoutNode(Size size) {
+        this.size = size;
+      }
+    }
+    #endregion
+
+    #region Mechanics
+    private class NodeMechanics {
+      public Node Node { get; private set; }
+      public Vector Velocity { get; set; }
+      public Point NextPosition { get; set; }
+
+      public NodeMechanics(Node node, Vector velocity, Point nextPosition) {
+        Node = node;
+        Velocity = velocity;
+        NextPosition = nextPosition;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/AlgorithmNodeRectangle.cs
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/AlgorithmNodeRectangle.cs	(revision 13832)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/AlgorithmNodeRectangle.cs	(revision 13833)
@@ -30,11 +30,37 @@
     protected readonly Brush ActiveBrush = new SolidBrush(Color.FromArgb(255, 100, 200, 100));
 
+    public new IAlgorithmNode NetworkItem {
+      get { return (IAlgorithmNode)base.NetworkItem; }
+      set { base.NetworkItem = value; }
+    }
+
     public AlgorithmNodeRectangle(IChart chart, IAlgorithmNode node)
       : base(chart, node) {
       Brush = InactiveBrush;
-      node.Algorithm.Started += (sender, args) => Brush = ActiveBrush;
-      node.Algorithm.Stopped += (sender, args) => Brush = InactiveBrush;
-      node.StartedAlgorithmsChanged += (sender, args) => Brush = ((IAlgorithmNode)sender).StartedAlgorithms.Any() ? ActiveBrush : InactiveBrush;
     }
+
+    protected override void RegisterNetworkItemEvents() {
+      base.RegisterNetworkItemEvents();
+      NetworkItem.StartedAlgorithmsChanged += NetworkItem_StartedAlgorithmsChanged;
+      if (NetworkItem.Algorithm != null) {
+        NetworkItem.Algorithm.Started += Algorithm_Started; ;
+        NetworkItem.Algorithm.Stopped += Algorithm_Stopped; ;
+      }
+    }
+
+    protected override void DeregisterNetworkItemEvents() {
+      if (NetworkItem.Algorithm != null) {
+        NetworkItem.Algorithm.Stopped -= Algorithm_Stopped; ;
+        NetworkItem.Algorithm.Started -= Algorithm_Started; ;
+      }
+      NetworkItem.StartedAlgorithmsChanged -= NetworkItem_StartedAlgorithmsChanged;
+      base.DeregisterNetworkItemEvents();
+    }
+
+    private void NetworkItem_StartedAlgorithmsChanged(object sender, System.EventArgs e) {
+      Brush = ((IAlgorithmNode)sender).StartedAlgorithms.Any() ? ActiveBrush : InactiveBrush;
+    }
+    private void Algorithm_Started(object sender, System.EventArgs e) { Brush = ActiveBrush; }
+    private void Algorithm_Stopped(object sender, System.EventArgs e) { Brush = InactiveBrush; }
   }
 }
Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/MessagePortRectangle.cs
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/MessagePortRectangle.cs	(revision 13832)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/MessagePortRectangle.cs	(revision 13833)
@@ -39,7 +39,26 @@
     public MessagePortRectangle(IChart chart, IMessagePort port, INode node)
       : base(chart, port, node) {
-      IdleBrush = new SolidBrush(VisualProperties.BrushColor);
-      port.MessageSent += (sender, args) => Highlight(MessageSentBrush);
-      port.MessageReceived += (sender, args) => Highlight(MessageReceivedBrush);
+      IdleBrush = Brush;
+    }
+
+    protected override void RegisterNetworkItemEvents() {
+      base.RegisterNetworkItemEvents();
+      NetworkItem.MessageSent += NetworkItem_MessageSent;
+      NetworkItem.MessageReceived += Port_MessageReceived;
+    }
+
+    protected override void DeregisterNetworkItemEvents() {
+      NetworkItem.MessageReceived -= Port_MessageReceived;
+      NetworkItem.MessageSent -= NetworkItem_MessageSent;
+      base.DeregisterNetworkItemEvents();
+    }
+
+    private void Port_MessageReceived(object sender, Common.EventArgs<IMessage, System.Threading.CancellationToken> e) {
+      Highlight(MessageReceivedBrush);
+    }
+
+
+    private void NetworkItem_MessageSent(object sender, Common.EventArgs<IMessage, System.Threading.CancellationToken> e) {
+      Highlight(MessageSentBrush);
     }
 
Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/NodeRectangle.cs
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/NodeRectangle.cs	(revision 13832)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/NodeRectangle.cs	(revision 13833)
@@ -255,8 +255,10 @@
     #region Helpers
     private void LoadVisualProperties() {
-      if (VisualProperties == null)
-        VisualProperties = new NodeVisualProperties();
-
-      var vp = VisualProperties;
+      INodeVisualProperties vp = new NodeVisualProperties();
+
+      if (networkItem != null)
+        if (VisualProperties == null) VisualProperties = vp;
+        else vp = VisualProperties;
+
       IgnoreVisualPropertiesChanges = true;
       try {
Index: /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/PortRectangle.cs
===================================================================
--- /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/PortRectangle.cs	(revision 13832)
+++ /branches/OptimizationNetworks/HeuristicLab.Networks.Views.NetworkVisualization/3.3/Primitives/PortRectangle.cs	(revision 13833)
@@ -205,8 +205,10 @@
     #region Helpers
     private void LoadVisualProperties() {
-      if (VisualProperties == null)
-        VisualProperties = new PortVisualProperties();
-
-      var vp = VisualProperties;
+      IPortVisualProperties vp = new PortVisualProperties();
+
+      if (networkItem != null)
+        if (VisualProperties == null) VisualProperties = vp;
+        else vp = VisualProperties;
+
       IgnoreVisualPropertiesChanges = true;
       try {
