예제 #1
0
        private void PositionRank(Graph graph, Rank rank, float xOffset)
        {
            var nodes = rank.Column;

            float totalHeight = nodes.Sum(n => n.ScaledSize);

            float freespace = 1 * graph.ScaledHeight - totalHeight;

            float ySpace = freespace / (nodes.Count + 1); // space between each block
            rank.MinNodeSpace = Math.Min(ySpace, 16);
            float yOffset = ySpace;

            foreach (var node in nodes)
            {
                node.ScaledLocation.X = xOffset;
                node.ScaledLocation.Y = 1 * graph.ScaledOffset + yOffset + node.ScaledSize / 2;

                yOffset += node.ScaledSize + ySpace;
            }
        }
예제 #2
0
        internal void Reset(int nodeCount, int edgeCount, int weightMax)
        {
            CallGraphOn = false;

            Nodes.Clear();
            Edges.Clear();

            NextID = 1;

            for (int i = 0; i < nodeCount; i++)
                Nodes.Add(new Node()
                {
                    ID = NextID++,
                    Weight = RndGen.Next(weightMax),
                    ScaledLocation = new PointF((float)RndGen.NextDouble(), (float)RndGen.NextDouble())
                });

            for (int i = 0; i < edgeCount; i++)
            {
                Edge edge = new Edge(Nodes[RndGen.Next(nodeCount)], Nodes[RndGen.Next(nodeCount)]);

                if (Edges.Any(e => e.Source == edge.Source && e.Destination == edge.Destination))
                    continue;

                Edges.Add(edge);

                edge.Source.Edges.Add(edge);
                edge.Destination.Edges.Add(edge);
            }

            Graphs.Clear();

            Nodes = Nodes.Where(n => !n.Filler).ToList();
            Nodes.ForEach(n => n.Rank = null);

            Edges = Edges.Where(e => !e.Filler).ToList();
            Edges.ForEach(e => e.Reset());

            // do while still more graph groups to process
            do
            {
                // group nodes into connected graphs
                Dictionary<int, Node> graph = new Dictionary<int, Node>();

                // add first unranked node to a graph
                Node node = Nodes.First(n => n.Rank == null);
                node.Layout(graph, 0, new List<Node>(), new List<string>());

                // while group contains unranked nodes
                while (graph.Values.Any(n => n.Rank == null))
                {
                    // head node to start traversal
                    node = graph.Values.First(n => n.Rank == null);

                    // only way node could be in group is if child added it, so there is a minrank
                    // min rank is 1 back from the lowest ranked child of the node
                    int? minRank = node.OutboundEdges.Min(e => e.Destination.Rank.HasValue ? e.Destination.Rank : int.MaxValue);

                    node.Layout(graph, minRank.Value - 1, new List<Node>(), new List<string>());
                }

                // normalize ranks so sequential without any missing between
                int i = -1;
                int currentRank = int.MinValue;
                foreach (var n in graph.Values.OrderBy(v => v.Rank))
                {
                    if (n.Rank != currentRank)
                    {
                        currentRank = n.Rank.Value;
                        i++;
                    }

                    n.Rank = i;
                }

                // put all nodes into a rank based multi-map
                Dictionary<int, Rank> rankMap = new Dictionary<int, Rank>();

                foreach (var n in graph.Values)
                {
                    int index = n.Rank.Value;

                    if (!rankMap.ContainsKey(index))
                        rankMap[index] = new Rank() { Order = index };

                    rankMap[index].Column.Add(n);
                }

                // once all nodes ranked, run back through and create any intermediate nodes
                foreach (var n in graph.Values)
                {
                    foreach (Edge edge in from e in n.Edges
                                          where e.Source == n
                                          select e)
                    {
                        Debug.Assert(edge.Source == edge.Destination || edge.Source.Rank < edge.Destination.Rank);

                        // create intermediate nodes
                        if (edge.Destination.Rank.Value > n.Rank.Value + 1)
                        {
                            // change edge destination to temp node, until rank equals true destination

                            Edge tempEdge = edge;
                            int nextRank = n.Rank.Value + 1;
                            Node target = edge.Destination;
                            edge.Destination = new Node(); // used as init for tempNode below

                            do
                            {
                                Node tempNode = tempEdge.Destination;
                                tempNode.ID = NextID++;
                                tempNode.Filler = true;
                                tempNode.Rank = nextRank;
                                tempNode.Weight = 3;

                                tempEdge.Destination = tempNode;
                                tempNode.Edges.Add(tempEdge);

                                rankMap[nextRank].Column.Add(tempNode);
                                graph[tempNode.ID] = tempNode;

                                Nodes.Add(tempNode);

                                tempEdge = new Edge(tempNode, new Node()) // initd above as tempNode
                                {
                                    Reversed = edge.Reversed,
                                    Filler = true
                                };

                                Edges.Add(tempEdge);

                                nextRank++;
                                if (nextRank == target.Rank.Value)
                                    tempEdge.Destination = target;

                            } while (tempEdge.Destination != target);

                            // TODO do need to add edge to assist in uncross?
                            // dont need to add inbound edge to real node because inbound edges
                            // only traversed in layout which is called before this
                            //target.Edges.Add(tempEdge);
                        }
                    }
                }

                Graphs.Add(new Graph() { Ranks = rankMap.Values.OrderBy(r => r.Order).ToList() });

            } while (Nodes.Any(n => n.Rank == null));

            Graphs = Graphs.OrderByDescending(g => g.Ranks.Sum(r => r.Column.Sum(n => n.Weight))).ToList();

            double totalWeight = Nodes.Sum(n => n.Weight);
            double totalArea = 1; // Width* Height;

            double weightToPix = totalArea / totalWeight * Reduce;

            Nodes.ForEach(n => n.ScaledSize = (float)Math.Sqrt(n.Weight * weightToPix));

            DoRedraw = true;
            Invalidate();
        }