Skip to content

Instantly share code, notes, and snippets.

@rossmurray
Created April 30, 2014 21:55
Show Gist options
  • Save rossmurray/d939466780c6e38077cb to your computer and use it in GitHub Desktop.
Save rossmurray/d939466780c6e38077cb to your computer and use it in GitHub Desktop.
Grouping absolutely-positioned elements into columns (table extraction).
public IList<IEnumerable<Rectangle>> GetColumns(IList<Rectangle> elements)
{
if(elements == null) throw new ArgumentNullException("elements");
if(!elements.Any()) return new List<IEnumerable<Rectangle>>();
var length = elements.Count();
if(length == 1) return new[]{elements.ToList()};
var sorted = elements.OrderBy(x => x.X).ToArray();
var firstElement = sorted.First();
var columns = new List<IEnumerable<Rectangle>>();
var columnContents = new List<Rectangle>(){firstElement};
var columnDimensions = new Rectangle(firstElement);
for (int i = 1; i < length; i++)
{
var current = sorted[i];
if(IntersectsX(current, columnDimensions))
{
columnContents.Add(current);
columnDimensions = new Rectangle
{
Width = (current.X + current.Width) - columnDimensions.X
};
}
else
{
columns.Add(columnContents);
columnContents = new List<Rectangle>(){current};
columnDimensions = new Rectangle(current);
}
}
if(columnContents.Any())
{
columns.Add(columnContents);
}
return columns;
}
public bool IntersectsX(Rectangle a, Rectangle b)
{
var ax2 = a.X + a.Width;
var bx2 = b.X + b.Width;
if(b.X > ax2) return false;
if(a.X > bx2) return false;
return true;
}
public class Rectangle
{
public float X;
public float Y;
public float Width;
public float Height;
public Rectangle(){}
public Rectangle(Rectangle o)
{
this.X = o.X;
this.Y = o.Y;
this.Width = o.Width;
this.Height = o.Height;
}
}
@rossmurray
Copy link
Author

One way to refactor this code is to map Rectangles to Segments, which only have X and X2 properties. Then you can reuse much of your code for both column- and row-grouping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment