diff --git a/OpenRA.FileFormats/ConnectedComponents.cs b/OpenRA.FileFormats/ConnectedComponents.cs index a1216cdb86..de43f975f3 100644 --- a/OpenRA.FileFormats/ConnectedComponents.cs +++ b/OpenRA.FileFormats/ConnectedComponents.cs @@ -14,7 +14,7 @@ namespace OpenRA.FileFormats { var result = new int[m.MapSize, m.MapSize]; var types = new int[m.MapSize, m.MapSize]; - var d = new Dictionary(); + var d = new Dictionary(); var n = 1; for( var j = m.YOffset; j < m.YOffset + m.Height; j++ ) @@ -23,14 +23,57 @@ namespace OpenRA.FileFormats types[i, j] = f(i, j); var k = n; - foreach (var a in Neighbors) - if (types[i + a.X, j + a.Y] == types[i, j] && result[i + a.X, j + a.Y] < k) - k = result[i + a.X, j + a.Y]; - // todo: finish this + foreach (var a in Neighbors) + if (types[i + a.X, j + a.Y] == types[i, j]) + k = (k == n) + ? result[i + a.X, j + a.Y] + : Union( d, k, result[i+a.X, j+a.Y] ); + + result[i,j] = k; + if (k == n) MakeSet(d, n++); } + for (var j = m.YOffset; j < m.YOffset + m.Height; j++) + for (var i = m.XOffset; i < m.XOffset + m.Width; i++) + result[i, j] = Find(d, result[i, j]); + return result; } + + // disjoint-set forest stuff + + class Node { public int a, b; public Node(int a, int b) { this.a = a; this.b = b; } } + + static int MakeSet(Dictionary d, int x) + { + d[x] = new Node(x, 0); + return x; + } + + static int Union(Dictionary d, int x, int y) + { + var xr = Find(d, x); + var yr = Find(d, y); + var xa = d[xr].b; + var ya = d[yr].b; + + if (xa > ya) d[yr].a = xr; + else if (xa < ya) d[xr].a = yr; + else if (xr != yr) + { + d[yr].a = xr; + ++d[xr].b; + } + + return xr; + } + + static int Find(Dictionary d, int x) + { + if (d[x].a == x) return x; + return d[x].a = Find(d, d[x].a); + } + } }