public static void RunGraph(Program.Args args) { SqliteInput input = new(args.DbPath); Dictionary <int, DbNode> nodes = input.DeSerialize(); ForceDirectedGraph forceDirectedGraph = new(args.RepulsiveForce, args.SpringForce); Dictionary <int, ForceDirectedGraph.Node> fdgNodes = new Dictionary <int, ForceDirectedGraph.Node>(); foreach ((int key, DbNode dbNode) in nodes) { ForceDirectedGraph.Node newNode = forceDirectedGraph.AddNodeToGraph((uint)key); newNode.Position = dbNode.Position; fdgNodes.Add(key, newNode); } foreach ((int key, DbNode dbNode) in nodes) { fdgNodes.TryGetValue(key, out ForceDirectedGraph.Node nodeA); foreach (int dependencyKey in dbNode.edgeIds) { fdgNodes.TryGetValue(dependencyKey, out ForceDirectedGraph.Node nodeB); nodeA?.MyEdges.Add((uint)dependencyKey); nodeB?.MyEdges.Add((uint)key); } } Vector3[] results = forceDirectedGraph.RunGraph(args.Iterations); Console.WriteLine($"Writing to {args.DbPath}"); SqliteOutput output = new(args.DbPath); output.Serialize(results); }
/// <summary> /// Adds the specified Node to this Diagram. /// </summary> /// <param name="node">The Node to add to the diagram.</param> /// <returns>True if the node was added, false if the node is already on this Diagram.</returns> public bool AddNode(Node node) { if (node == null) throw new ArgumentNullException("node"); if (!mNodes.Contains(node)) { // add node, associate with diagram, then add all connected nodes mNodes.Add(node); node.Diagram = this; foreach (Node child in node.Connections) { AddNode(child); } return true; } else { return false; } }
/// <summary> /// Draws a connector between this node and the specified child node using GDI+. /// The source and destination coordinates (relative to the Graphics surface) are also specified. /// </summary> /// <param name="graphics">GDI+ Graphics surface.</param> /// <param name="from">Source coodinate.</param> /// <param name="to">Destination coordinate.</param> /// <param name="other">The other node.</param> public virtual void DrawConnector(Graphics graphics, Point from, Point to, Node other) { graphics.DrawLine(Pens.Gray, surface.SurfaceOffsetAdjust(from), surface.SurfaceOffsetAdjust(to)); }
/// <summary> /// Removes any connection between this node and the specified node. /// </summary> /// <param name="other">The other node whose connection is to be removed.</param> /// <returns>True if a connection existed.</returns> public bool Disconnect(Node other) { bool c = this.mConnections.Remove(other); bool p = other.mConnections.Remove(this); return c || p; }
/// <summary> /// Connects this node to the specified parent node. /// </summary> /// <param name="parent">The node to connect to this node.</param> /// <returns>True if the other node was connected to this node.</returns> public bool AddParent(Node parent) { if (parent == null) throw new ArgumentNullException("parent"); return parent.AddChild(this); }
/// <summary> /// Connects the specified child node to this node. /// </summary> /// <param name="child">The child node to add.</param> /// <returns>True if the node was connected to this node.</returns> public bool AddChild(Node child) { if (child == null) throw new ArgumentNullException("child"); if ((child != this) && !this.mConnections.Contains(child)) { child.Diagram = this.Diagram; this.mConnections.Add(child); return true; } else { return false; } }
/// <summary> /// Adds the specified Node to this Diagram. /// </summary> /// <param name="node">The Node to add to the diagram.</param> /// <returns>True if the node was added, false if the node is already on this Diagram.</returns> public bool AddNode(Node node) { bool ret = false; if (node == null) throw new ArgumentNullException("node"); if (!nodes.Contains(node)) { // add node, associate with diagram, then add all connected nodes nodes.Add(node); node.Diagram = this; layout.Add(new NodeLayoutInfo(node, new Vector(), node.Location)); foreach (Node child in node.Connections) { AddNode(child); } ret = true; } return ret; }
public Vector Velocity; // the node's current velocity, expressed in vector form #endregion Fields #region Constructors /// <summary> /// Initialises a new instance of the Diagram.NodeLayoutInfo class, using the specified parameters. /// </summary> /// <param name="node"></param> /// <param name="velocity"></param> /// <param name="nextPosition"></param> public NodeLayoutInfo(Node node, Vector velocity, PointF nextPosition) { Node = node; Velocity = velocity; NextPosition = nextPosition; }
/// <summary> /// Calculates the repulsion force between any two nodes in the diagram space. /// </summary> /// <param name="x">The node that the force is acting on.</param> /// <param name="y">The node creating the force.</param> /// <returns>A Vector representing the repulsion force.</returns> private Vector CalcRepulsionForce(Node x, Node y) { double proximity = Math.Max(CalcDistance(x.Location, y.Location), 1); // Coulomb's Law: F = k(Qq/r^2) double force = -(REPULSION_CONSTANT / Math.Pow(proximity, 2)); double angle = GetBearingAngle(x.Location, y.Location); return new Vector(force, angle); }
/// <summary> /// Calculates the attraction force between two connected nodes, using the specified spring length. /// </summary> /// <param name="x">The node that the force is acting on.</param> /// <param name="y">The node creating the force.</param> /// <param name="springLength">The length of the spring, in pixels.</param> /// <returns>A Vector representing the attraction force.</returns> private Vector CalcAttractionForce(Node x, Node y, double springLength) { double proximity = Math.Max(CalcDistance(x.Location, y.Location), 1); // Hooke's Law: F = -kx double force = ATTRACTION_CONSTANT * Math.Max(proximity - springLength, 0); double angle = GetBearingAngle(x.Location, y.Location); return new Vector(force, angle); }
/// <summary> /// Removes the specified node from the diagram. Any connected nodes will remain on the diagram. /// </summary> /// <param name="node">The node to remove from the diagram.</param> /// <returns>True if the node belonged to the diagram.</returns> public bool RemoveNode(Node node) { bool ret; // Disconnect this node from other nodes. foreach (Node other in nodes) { if ((other != node) && other.Connections.Contains(node)) { other.Disconnect(node); } } ret = nodes.Remove(node); layout.Remove(layout.Single(n => n.Node == node)); return ret; }
/// <summary> /// Determines whether the diagram contains the specified node. /// </summary> /// <param name="node">The node to test.</param> /// <returns>True if the diagram contains the node.</returns> public bool ContainsNode(Node node) { return nodes.Contains(node); }
/// <summary> /// Removes the specified node from the diagram. Any connected nodes will remain on the diagram. /// </summary> /// <param name="node">The node to remove from the diagram.</param> /// <returns>True if the node belonged to the diagram.</returns> public bool RemoveNode(Node node) { node.Diagram = null; foreach (Node other in mNodes) { if ((other != node) && other.Connections.Contains(node)) other.Disconnect(node); } return mNodes.Remove(node); }
/// <summary> /// Draws a connector between this node and the specified child node using GDI+. /// The source and destination coordinates (relative to the Graphics surface) are also specified. /// </summary> /// <param name="graphics">GDI+ Graphics surface.</param> /// <param name="from">Source coodinate.</param> /// <param name="to">Destination coordinate.</param> /// <param name="other">The other node.</param> public virtual void DrawConnector(Graphics graphics, PointF from, PointF to, Node other) { graphics.DrawLine(Pens.Gray, from, to); }