我编写了自己的矩形类,它包含了一个从另一个矩形中减去一个矩形的方法。该算法简单地确定源矩形在目标矩形上重叠的边缘,然后突破所有可能的情况,包括完全在内部,仅在边缘,完全封闭等等。实际上有很多情况我会查看代码,并想知道是否有可用于矩形的布尔运算的算法或示例。
我知道有generalised clipping algorithms for 2d polytopes但我正在寻找特定于2d矩形的东西,并进行适当的优化和简化。
任何人都可以指出我正确的方向,或者Weiler-Atherton是这个普通类问题的最后一个词,矩形只是一个案例?
答案 0 :(得分:1)
如果将两个方向分开,则只有几个基本情况,然后可以在嵌套循环中组合。
基本案例概述如下:
| |
XXXXX |..............| 1 section
| |
XXXXXXX...........| 2 sections
| |
|...XXXXXXX....| 3 sections
| |
|..........XXXXXXXX 2 secions
| |
|..............| XXXX 1 section
| |
XXXXXXXXXXXXXXXXXXXX nothing
| |
垂直条纹是原始矩形的边缘,X
是要减去的矩形,点标记部分。垂直条之间的X
也是保留的部分,除非与另一个方向的X
部分组合。 (如果这听起来太复杂了:留下的洞是由X
部分在两个方向指定的。
我们可以通过将左,上,右和底的矩形属性重新设计为最小/最大值数组来分离方向:
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 + 1
个部分之间创建一个n
边界数组。 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;
}
此解决方案不是最佳选择。当第二个矩形包含在第一个矩形中时,它将创建八个矩形,这可能不是您要查找的。您可以随后尝试合并相邻的矩形。或者你可以重写代码以更智能地分割矩形。
我已经在某些情况下对代码进行了测试,但由于存在许多可能的安排,因此代码未经过全面测试。