如果将两个方向分开,则只有几个基本情况,然后可以将它们组合在一个嵌套循环中。
基本情况如下:
| |
XXXXX |..............| 1 section
| |
XXXXXXX...........| 2 sections
| |
|...XXXXXXX....| 3 sections
| |
|..........XXXXXXXX 2 secions
| |
|..............| XXXX 1 section
| |
XXXXXXXXXXXXXXXXXXXX nothing
| |
竖线是原始矩形的边缘,X 是要减去的矩形,点标记部分。垂直条之间的X 也是保留的部分,除非与另一个方向的X 部分结合使用。 (如果这听起来太复杂:留下的洞由X 部分在两个方向上指定。
我们可以通过将矩形属性 left、top、right 和 bottom 重新设计为最小/最大值数组来分离方向:
typedef struct Rect Rect;
struct Rect {
int min[2];
int max[2];
};
(恐怕代码是C,不是C++。)
然后我们可以找到每个方向的部分:
int rect_sub_dir(int sec[], int *skip, Rect a, Rect b, int dir)
{
int n = 0;
sec[n++] = a.min[dir];
if (b.min[dir] > a.min[dir] && b.min[dir] < a.max[dir]) {
sec[n++] = b.min[dir];
}
*skip = n - 1;
if (b.max[dir] < a.max[dir] && b.max[dir] > a.min[dir]) {
sec[n++] = b.max[dir];
}
sec[n] = a.max[dir];
// Backpatch if rectangles don't overlap
if (b.max[dir] < a.min[dir]) *skip = -1;
if (b.min[dir] > a.max[dir]) *skip = -1;
return n;
}
这会在n 部分之间创建一个n + 1 边界数组。 skip 值表示在竖线之间标记为 X 的部分。
然后您可以将两个方向的部分组合起来:
int rect_sub(Rect res[], Rect a, Rect b)
{
int hor[4];
int ver[4];
int hskip, nhor;
int vskip, nver;
int h, v;
int n = 0;
nhor = rect_sub_dir(hor, &hskip, a, b, 0);
nver = rect_sub_dir(ver, &vskip, a, b, 1);
printf("%d, %d\n", hskip, vskip);
for (h = 0; h < nhor; h++) {
for (v = 0; v < nver; v++) {
if (h == hskip && v == vskip) continue;
res[n++] = rect(hor[h], ver[v], hor[h + 1], ver[v + 1]);
}
}
return n;
}
这个解决方案不是最优的。当第二个矩形包含在第一个矩形中时,它将创建八个矩形,这可能不是您想要的。之后您总是可以尝试合并相邻的矩形。或者您可以重写代码以更智能地分割矩形。
我已经用一些案例测试了代码,但是因为有很多可能的安排,所以代码没有完全测试。