public FDLEdge(FDLNode source, FDLNode target, Vector ideal) : base(source, target) { this.ideal = ideal; InvalidateEdge(); }
/// <summary> /// Initializes this force-directed layout. Assumes that graph has some /// reasonable initial node positions. /// </summary> /// <param name="graph">The graph to layout.</param> /// <param name="start_node">The node to start layout from.</param> public ForceDirectedLayout(IReadOnlyGraph<FDLNode, FDLEdge> graph, FDLNode start_node) { if (graph == null) throw new ArgumentNullException("graph"); if (start_node == null) throw new ArgumentNullException("start_node"); if (!graph.ContainsNode(start_node)) throw new ArgumentException("start_node must be in this graph"); //initialize nodes array to only the reachable nodes ArrayList n = new ArrayList(graph.NodeCount); Algorithms.Algorithms.BreadthFirstSearch(graph, start_node, null, delegate(FDLNode node){ n.Add(node); }); nodes = new FDLNode[n.Count]; n.CopyTo(nodes); new_positions = new MutablePoint[nodes.Length]; accels = new double[nodes.Length]; //summarize constraints HashSet<FDLEdge> h = new HashSet<FDLEdge>(); for (int i = 0; i < nodes.Length; i++) { foreach (FDLEdge edge in nodes[i].OutEdges) { DefaultEdge reverse = edge.Target.GetEdgeTo(edge.Source); if(h.Contains(edge) || (reverse != null && h.Contains(reverse))) continue; h.Add(edge); } } constraints = new FDLEdge[h.Count]; h.CopyTo(constraints); }
/// <summary> /// Create a new FDLEdge leading from the source to the target. /// </summary> /// <param name="source"></param> /// <param name="target"></param> public FDLEdge(FDLNode source, FDLNode target) : this(source, target, Point.Delta(source.Position, target.Position)) { }
private static Vector NodeNodeForce(FDLNode node1, FDLNode node2) { // distance squared for a small perf improvement double distance_s = NodeDistanceSquared(node1, node2); // composite function, must be continuous if (distance_s >= 4.0 * K_SQUARED) { return Vector.ZERO_VECTOR; } else if (distance_s > K_SQUARED) { double distance = Math.Sqrt(distance_s); double repulsion = Math.Min(-1.0 * distance / K + 2.0, K); double angle = NodeAngle(node2, node1); return Vector.FromPolar(repulsion, angle); } else if (distance_s > 0) { double repulsion = Math.Min(K_SQUARED / distance_s, K); double angle = NodeAngle(node2, node1); return Vector.FromPolar(repulsion, angle); } else { return Vector.ZERO_VECTOR; } }
private static double NodeDistanceSquared(FDLNode node1, FDLNode node2) { Point v1 = node1.Position; Point v2 = node2.Position; double dx = v1.X - v2.X; double dy = v1.Y - v2.Y; return dx * dx + dy * dy; }
private static double NodeAngle(FDLNode from, FDLNode to) { FDLEdge e = from.GetEdgeTo(to) as FDLEdge; if (e != null) return e.Angle; return Vector.CalcAngle(from.Position, to.Position); }