这是一种不使用光栅化的方法,即仅使用纯数字。
注意:这不是 O(n log n),更像是 O(n^2)。然而,它是一个解决方案。是否是答案,如果 O(n log n) 是要求,则可能不是。
- 创建一个包含左右边缘的所有唯一 X 坐标的列表(在同一个列表中)
- 在构建此列表时,对于每个坐标,还要将一个矩形列表与其关联,并在此列表中表示与该列表关联的 X 坐标是矩形的左边缘还是右边缘
- 对坐标列表进行排序,使其从左到右升序
- 创建一个新的矩形列表,最初为空
- 遍历坐标列表,并为其处理相关的矩形列表
- 关联列表中所有以坐标为左边缘的矩形都应添加到您在 4 中创建的列表中。
- 应删除所有以坐标为右边缘的矩形。
- 添加和删除的顺序实际上应该以相反的顺序完成,首先要删除右边缘矩形,然后添加所有左边缘矩形
- 现在,在从 4 中创建的列表中删除矩形之前,您需要对其进行处理。您通过将它们视为“子矩形”来处理它们。它们的“新”左边缘坐标是您处理循环的上一次迭代(在 5 中)的 X 坐标,新的右边缘是正在处理的当前 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
List 包含矩形,将列表处理为具有 X=1 左边缘和 X=2 右边缘的矩形(我们到目前为止处理的两个坐标),并使用它们的原始顶部和底部坐标。
没有什么可以删除的。
添加 B:L=[ A, B ]
X=3
List包含矩形,处理list(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。
条看起来像这样:
^ +----+ <-- 1
A | |
| ^ +----+ <-- 2
| C | |
| ^ | +----+ <-- 3
| B | | |
| | V +----+ <-- 4
| | | |
V | +----+ <-- 5
| | |
V +----+ <-- 6
矩形坐标列表:
- 顶部=A,底部=(无)
- 顶部=C,底部=(无)
- 顶部=B,底部=(无)
- 顶部=(无),底部=C
- 顶部=(无),底部=A
- 顶部=(无),底部=B
新建空列表 L=[]
处理坐标:
Y=1
无需处理 (L=[])
将 A 添加到列表中,L=[ A ]
Y=2
进程 A 的顶部和底部坐标暂时为 Y=1 和 2(请记住,它还具有临时的左右坐标 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, Bli>
- (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,基本上是一个值到另一个值的范围,所以除了上面的算法,还有一点数据的构建和维护。