这是一种不使用光栅化的方法,即仅使用纯数字。
注意:这不是 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 包含矩形,将 list 处理为具有 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。
条看起来像这样:
^ +----+ <-- 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) 的临时坐标 Add 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 基本上是一个值到另一个值的范围,所以除了上面的算法之外,还有一点数据的构建和维护。