public ClusterTestNode(ClusterPart Parent, bool Top) { this.Parent = Parent; this.IsTop = Top; Y = Top ? Parent.Rectangle.Top : Parent.Rectangle.Bottom; }
List <Cluster> ClusterRanges(IEnumerable <List <Rectangle> > ranges) { ClustersFinished = false; List <ClusterTestNode> tests = new List <ClusterTestNode>(); ranges.ForEach(rrl => { rrl.ForEach(rr => { ClusterPart toAdd = new ClusterPart(rr); tests.Add(new ClusterTestNode(toAdd, true)); tests.Add(new ClusterTestNode(toAdd, false)); } ); }); tests.Sort((a, b) => { //sort by y, if ys are same, bottoms are first int ydif = a.Y - b.Y; if (0 != ydif) { return(ydif); } return(a.IsTop.CompareTo(b.IsTop)); }); List <Cluster> Clusters = new List <Cluster>(); Stack <int> searchStack = new Stack <int>(); int max = tests.Count; for (int i = max - 1; i >= 0; --i) { ClusterTestNode CurrentNode = tests[i]; if (!CurrentNode.IsTop) { continue; //if it is a bottom or is already in a cluster, nothing is done } if (CurrentNode.Parent.Cluster == null) { //Console.WriteLine("\nTesting "+CurrentNode.Parent.Rectangle); Cluster CurrentCluster = new Cluster(); Clusters.Add(CurrentCluster); searchStack.Push(i); while (searchStack.Count > 0) { //search for contacts if (IsCancelRequested) { goto endloop; } int searchIndex = searchStack.Pop(); ClusterTestNode SearchNode = tests[searchIndex]; //Console.WriteLine("\tSearch Seed: "+SearchNode.Parent.Rectangle); if (SearchNode.Parent.Cluster != null) { continue; } SearchNode.Parent.Cluster = CurrentCluster; CurrentCluster.Ranges.Add(SearchNode.Parent.Rectangle); //search up for bottoms for (int s = searchIndex - 1; s >= 0; --s) { if (!tests[s].IsTop) { if (tests[s].Y == SearchNode.Parent.Rectangle.Top && OverlapsX(tests[s].Parent.Rectangle, SearchNode.Parent.Rectangle)) { searchStack.Push(s); } else if (tests[s].Y < SearchNode.Parent.Rectangle.Top) { //Console.WriteLine("\t\tStopped at "+s); break; } } } //search down for tops for (int s = searchIndex + 1; s < max; ++s) { if (tests[s].IsTop) { if (tests[s].Y == SearchNode.Parent.Rectangle.Bottom && OverlapsX(tests[s].Parent.Rectangle, SearchNode.Parent.Rectangle)) { searchStack.Push(s); } else if (tests[s].Y > SearchNode.Parent.Rectangle.Bottom) { //Console.WriteLine("\t\tStopped at "+s); break; } } } } } } ClustersFinished = true; endloop: return(Clusters); }