这里有一种方法可以在不使用光栅化的情况下完成,也就是只使用纯数字。
注意:这不是O(n log n),更像是O(n^2)。然而,它是一种解决方案。是否是答案,如果需要O(n log n)的话可能不是。
- 创建一个包含所有左右边缘唯一X坐标的列表(在同一个列表中)
- 当您构建此列表时,对于每个坐标,还要将其与矩形列表相关联,并在此列表中指示该列表关联的X坐标是矩形的左侧还是右侧边缘
- 对坐标列表进行排序,使其按升序排列,从左到右
- 创建一个新的矩形列表,最初为空
- 遍历坐标列表,并处理与之相关联的矩形列表
- 所有在相关联列表中被标记为具有该坐标作为左侧边缘的矩形都应添加到第4步中创建的列表中。
- 所有具有该坐标作为右侧边缘的矩形都应被删除。
- 添加和删除的顺序实际上应该相反,首先要删除右侧边缘矩形,然后添加所有左侧边缘矩形
- 现在,在从第4步中创建的列表中删除矩形之前,您需要处理它们。通过将它们视为“子矩形”来处理它们。它们的“新”左侧边缘坐标是您在上一次循环迭代中处理的X坐标(在第5步中),而新的右侧边缘是正在处理的当前X坐标
- 算法的输出是一组坐标对(两个X坐标左和右),每个对都有一个相关联的矩形列表(垂直条)
因此输出应为:
- X=1..2,矩形区域=A
- X=2..3,矩形区域=A、B
- X=3..4,矩形区域=A、B、C
- X=4..5,矩形区域=A、C
- X=5..6,矩形区域=C
让我来说明一下目前的过程
+-------------------+
|A |
| +----------+-----+
| |C | |
| +-----+----+ | |
| |B | | | |
| | +----+-----+-----+
| | | |
+--+----------+-----+
| |
+----------+
^ ^ ^ ^ ^ ^
1 2 3 4 5 6 <-- X-coordinates
相关矩形:
- 左:A,右:(无)
- 左:B,右:(无)
- 左:C,右:(无)
- 左:(无),右:B
- 左:(无),右:A
- 左:(无),右:C
现在创建一个空列表L=[]
,并开始处理坐标和相关矩形:
X=1
列表为空,没有要处理的内容
没有要删除的内容
添加A:L=[ A ]
X=2
列表包含矩形,将列表中具有X=1左边缘和X=2右边缘(我们已经处理了两个坐标)的矩形作为矩形进行处理,并使用它们的原始顶部和底部坐标。
没有要删除的内容。
添加B:L=[ A, B ]
X=3
列表包含矩形,以相同方式处理列表中的A和B,将它们视为暂时具有左坐标和右坐标为X=2和X=3,并使用它们的原始顶部和底部坐标。
没有要删除的内容
添加C:L=[ A, B, C ]
X=4
以与上述相同的方式处理三个矩形,临时左右坐标为X=3和X=4
移除B:L=[A,C]
无需添加
X=5和X=6
以完全相同的方式处理这些内容。
这意味着您最终将得到矩形“条”,就像这样(我稍微拉开它们以更清楚地说明它们是条纹,但它们像原始图表中连续并排放置):
+--+ +-----+ +----+ ------+
|A | | | | | | |
| | | | +----+ +-----+ +-----+
| | | | |C | | | | |
| | +-----| +----+ | | | |
| | |B | | | | | | |
| | | | +----+ +-----| +-----+
| | | | | | | |
+--+ +-----+ +----+ +-----+
| | | |
+-----+ +----+
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
1 2 2 3 3 4 4 5 5 6
好的,现在你有了输出结果,一个坐标对的集合,每个坐标对都有一个关联的矩形列表。
现在我们来做一个小技巧。我们以完全相同的方式处理垂直条带,只是这一次我们使用Y坐标作为分隔符。让我们处理上面3和4之间的条带。请记住,该条带具有左右坐标3和4。
条带看起来像这样:
^ +
A | |
| ^ +
| C | |
| ^ | +
| B | | |
| | V +
| | | |
V | +
| | |
V +
带有矩形的坐标列表:
- 顶部=A,底部=(无)
- 顶部=C,底部=(无)
- 顶部=B,底部=(无)
- 顶部=(无),底部=C
- 顶部=(无),底部=A
- 顶部=(无),底部=B
新的空列表L=[]
处理坐标:
Y=1
没有要处理的内容(L=[])
将A添加到列表中,L=[ A ]
Y=2
使用临时的顶部和底部坐标为Y=1和2来处理A(并记住它还具有X=3和4的临时左右坐标)
添加C,L=[ A, C ]
Y=3
处理A和C,两者现在都具有(3, 2)-(4, 3)的临时坐标
添加B,L=[ A, B, C ]
Y=4
处理A、B和C,所有坐标都为(3, 3)-(4, 4)
删除C,L=[ A, B ]
Y=5
进程A和B,坐标(3,4)-(4,5)
移除A,L=[B]
Y=6
进程B,坐标(3,5)-(4,6)
最终输出:
与矩形相关联的Y坐标对(它们也暂时获得了新的X坐标):
- (3,1)-(4,2)- A
- (3,2)-(4,3)- A,C
- (3,3)-(4,4)- A,B,C
- (3,4)-(4,5)- A,B
- (3,5)-(4,6)- B
现在,假设您想问一个问题:B是否被其他矩形的任何组合完全覆盖。
答案可以按以下方式计算:
遍历上述最终列表中的所有矩形;如果B不是关联矩形的一部分,请忽略此矩形;如果任何其他原始矩形与坐标相关联,则B的此部分由该/这些矩形覆盖;如果没有其他原始矩形与坐标相关联,则该B的部分未被覆盖。在上面的示例中,我们看到最终列表中的第3个和第4个矩形包含B,但还包含其他矩形,因此这些部分的B被覆盖,但列表中的最后一个矩形也包含B,但没有其他矩形,因此此部分未被覆盖。根据原始图表,最终结果将包括以下矩形(每个内部的字母表示与此新矩形关联的原始矩形):
+--+-----+----+-----+
|A |A |A |A |
| | +----+-----+-----+
| | |AC |AC |C |
| +-----+----+ | |
| |AB |ABC | | |
| | +----+-----+-----+
| | |AB |A |
+--+-----+----+-----+
|B |B |
+-----+----+
如果我们现在重新审视原始图表,我已经阴影标出了上述算法会发现包含B但没有其他矩形的部分:
+
|A |
| +
| |C | |
| +
| |B | | | |
| | +
| | | |
+
|#####|####|
+
中间的竖杠是为了说明该部分将被分成两个矩形,由于垂直条带的工作方式而在该位置分割。
我真诚地希望我在这里讲得明白。我有一些代码可以帮助你实现每次运行坐标列表,但现在已经是午夜01:21,我要去睡觉了,如果你想看到实际代码,请留下评论。
或者,自己实现它将是一个很好的练习 :)
这是包含所讨论方法的类的链接:RangeExtensions.cs。
方法是 Slice
方法,请在页面上搜索它。所讨论的类型 Range 基本上是从一个值到另一个值的范围,因此除了上述算法之外,还需要一些数据构造和维护。
O(n log n)
的算法,它基于对qsort
算法的改进。 - Matthieu M.