As you can see the below code for each method is that same, except for the properties it uses. For example X
vs Y
and Width
vs Height
. Is there anyway that I can refactor the code to use a common main method that changes on which property it uses?
Notes:
The all caps constant is BOX_LINEUP_TOLERANCE
has a value of 0.15f
and is all caps due to a company policy.
The two methods:
private List<Rectangle[]> GroupRectanglesHorizontally(Rectangle[] rectangles, out int averageGap)
{
List<int> nlGaps = new List<int>();
List<Rectangle[]> rectangleGroups = new List<Rectangle[]>();
for (int bi = 0, bc = rectangles.Length; bi < bc; ++bi)
{
if (rectangleGroups.Any(g => g.Contains(rectangles[bi])))
{
continue;
}
int nTolerance = (int)Math.Ceiling(rectangles[bi].Height * BOX_LINEUP_TOLERANCE);
Rectangle[] baSimiliarHeight = rectangles.Where(b => Math.Abs(b.Y - rectangles[bi].Y) <= nTolerance
&& b.X > rectangles[bi].X)
.ToArray();
if (baSimiliarHeight.Length <= 1)
{
rectangleGroups.Add(new Rectangle[] { rectangles[bi] });
continue;
}
baSimiliarHeight = baSimiliarHeight.OrderBy(b => b.X).ToArray();
int nInitialGap = baSimiliarHeight[0].X - (rectangles[bi].X + rectangles[bi].Width);
int nInitialGapTolerance = (int)Math.Ceiling(nInitialGap * BOX_LINEUP_TOLERANCE);
nlGaps.Add(nInitialGap);
List<Rectangle> rectangleList = new List<Rectangle>();
rectangleList.Add(rectangles[bi]);
rectangleList.Add(baSimiliarHeight[0]);
for (int sbi = 1; sbi < baSimiliarHeight.Length; ++sbi)
{
int nGap = baSimiliarHeight[sbi].X - (baSimiliarHeight[sbi - 1].X + baSimiliarHeight[sbi - 1].Width);
if (nGap <= nInitialGap + nInitialGapTolerance && nGap >= nInitialGap - nInitialGapTolerance)
{
rectangleList.Add(baSimiliarHeight[sbi]);
nlGaps.Add(nGap);
}
else if (nGap > nInitialGap)
{
break;
}
else
{
//Initial gap was larger so first rectangle is in its own group
rectangleList = new List<Rectangle>(new Rectangle[] { rectangles[bi] });
break;
}
}
rectangleGroups.Add(rectangleList.ToArray());
}
averageGap = (int)nlGaps.Average();
return rectangleGroups;
}
private List<Rectangle[]> GroupRectanglesVertically(Rectangle[] rectangles, out int averageGap)
{
List<int> nlGaps = new List<int>();
List<Rectangle[]> rectangleGroups = new List<Rectangle[]>();
for (int bi = 0, bc = rectangles.Length; bi < bc; ++bi)
{
if (rectangleGroups.Any(g => g.Contains(rectangles[bi])))
{
continue;
}
int nTolerance = (int)Math.Ceiling(rectangles[bi].Width * BOX_LINEUP_TOLERANCE);
Rectangle[] baSimiliarWidth = rectangles.Where(b => Math.Abs(b.X - rectangles[bi].X) <= nTolerance
&& b.Y > rectangles[bi].Y)
.ToArray();
if (baSimiliarWidth.Length <= 1)
{
rectangleGroups.Add(new Rectangle[] { rectangles[bi] });
continue;
}
baSimiliarWidth = baSimiliarWidth.OrderBy(b => b.Y).ToArray();
int nInitialGap = baSimiliarWidth[0].Y - (rectangles[bi].Y + rectangles[bi].Height);
int nInitialGapTolerance = (int)Math.Ceiling(nInitialGap * BOX_LINEUP_TOLERANCE);
nlGaps.Add(nInitialGap);
List<Rectangle> rectangleList = new List<Rectangle>();
rectangleList.Add(rectangles[bi]);
rectangleList.Add(baSimiliarWidth[0]);
for (int sbi = 1; sbi < baSimiliarWidth.Length; ++sbi)
{
int nGap = baSimiliarWidth[sbi].Y - (baSimiliarWidth[sbi - 1].Y + baSimiliarWidth[sbi - 1].Height);
if (nGap <= nInitialGap + nInitialGapTolerance && nGap >= nInitialGap - nInitialGapTolerance)
{
rectangleList.Add(baSimiliarWidth[sbi]);
nlGaps.Add(nGap);
}
else if (nGap > nInitialGap)
{
break;
}
else
{
//Initial gap was larger so first rectangle is in its own group
rectangleList = new List<Rectangle>(new Rectangle[] { rectangles[bi] });
break;
}
}
rectangleGroups.Add(rectangleList.ToArray());
}
averageGap = (int)nlGaps.Average();
return rectangleGroups;
}
I will also appreciate general feedback about the code.