这是我建议的方法:
- 清理这两个列表,这样就没有任何完全包含的“小”行。
- 选择任何一条线。
- 取所有接触(相交)这条线的线。
- 对于这些线中的每一条,取所有接触它们的线。
- 继续,直到你找不到更多的接触线。
- 你现在有一个组。
- 从剩下的行中选择一条并重复,直到没有更多的行。
代码:
public static IEnumerable<IEnumerable<Line>> Group(IEnumerable<Line> horizontalLines, IEnumerable<Line> verticalLines)
{
// Clean the input lists here. I'll leave the implementation up to you.
var ungroupedLines = new HashSet<Line>(horizontalLines.Concat(verticalLines));
var groupedLines = new List<List<Line>>();
while (ungroupedLines.Count > 0)
{
var group = new List<Line>();
var unprocessedLines = new HashSet<Line>();
unprocessedLines.Add(ungroupedLines.TakeFirst());
while (unprocessedLines.Count > 0)
{
var line = unprocessedLines.TakeFirst();
group.Add(line);
unprocessedLines.AddRange(ungroupedLines.TakeIntersectingLines(line));
}
groupedLines.Add(group);
}
return groupedLines;
}
public static class GroupingExtensions
{
public static T TakeFirst<T>(this HashSet<T> set)
{
var item = set.First();
set.Remove(item);
return item;
}
public static IEnumerable<Line> TakeIntersectingLines(this HashSet<Line> lines, Line line)
{
var intersectedLines = lines.Where(l => l.Intersects(line)).ToList();
lines.RemoveRange(intersectedLines);
return intersectedLines;
}
public static void RemoveRange<T>(this HashSet<T> set, IEnumerable<T> itemsToRemove)
{
foreach(var item in itemsToRemove)
{
set.Remove(item);
}
}
public static void AddRange<T>(this HashSet<T> set, IEnumerable<T> itemsToAdd)
{
foreach(var item in itemsToAdd)
{
set.Add(item);
}
}
}
将此方法添加到 Line
public bool Intersects(Line other)
{
// Whether this line intersects the other line or not.
// I'll leave the implementation up to you.
}
笔记:
如果此代码运行速度太慢,您可能需要水平扫描,边走边拾取连接线。可能也值得一看。
专门:
public static IEnumerable<IEnumerable<Line>> Group(IEnumerable<Line> horizontalLines, IEnumerable<Line> verticalLines)
{
// Clean the input lists here. I'll leave the implementation up to you.
var ungroupedHorizontalLines = new HashSet<Line>(horizontalLines);
var ungroupedVerticalLines = new HashSet<Line>(verticalLines);
var groupedLines = new List<List<Line>>();
while (ungroupedHorizontalLines.Count + ungroupedVerticalLines.Count > 0)
{
var group = new List<Line>();
var unprocessedHorizontalLines = new HashSet<Line>();
var unprocessedVerticalLines = new HashSet<Line>();
if (ungroupedHorizontalLines.Count > 0)
{
unprocessedHorizontalLines.Add(ungroupedHorizontalLines.TakeFirst());
}
else
{
unprocessedVerticalLines.Add(ungroupedVerticalLines.TakeFirst());
}
while (unprocessedHorizontalLines.Count + unprocessedVerticalLines.Count > 0)
{
while (unprocessedHorizontalLines.Count > 0)
{
var line = unprocessedHorizontalLines.TakeFirst();
group.Add(line);
unprocessedVerticalLines.AddRange(ungroupedVerticalLines.TakeIntersectingLines(line));
}
while (unprocessedVerticalLines.Count > 0)
{
var line = unprocessedVerticalLines.TakeFirst();
group.Add(line);
unprocessedHorizontalLines.AddRange(ungroupedHorizontalLines.TakeIntersectingLines(line));
}
}
groupedLines.Add(group);
}
return groupedLines;
}
这假设没有线重叠,因为它不检查水平线是否接触其他水平线(垂直相同)。
您可能可以删除 if-else。如果有垂直线未连接到水平线,那只是在那里。