可能最有效的方法是计算矩形-矩形减法,这在很多情况下可能看起来很困难,但实际上并不那么难:
struct Rect{
int x0, y0, x1, y1;
Rect(int x0, int y0, int x1, int y1)
: x0(x0), y0(y0), x1(x1), y1(y1)
{}
};
std::vector<Rect> subtract(const Rect& a, const Rect& b) {
std::vector<Rect> result;
if (a.y1 <= b.y0 || a.y0 >= b.y1 || a.x1 <= b.x0 || a.x0 >= b.x1) {
// Trivial case: rectangles are not overlapping
result.push_back(a);
} else {
int ystart = a.y0, yend = a.y1;
if (ystart < b.y0) { // Something visible above
result.push_back(Rect(a.x0, ystart, a.x1, b.y0));
ystart = b.y0;
}
if (yend > b.y1) { // Something visible below
result.push_back(Rect(a.x0, b.y1, a.x1, yend));
yend = b.y1;
}
if (a.x0 < b.x0) { // Something visible on the left
result.push_back(Rect(a.x0, ystart, b.x0, yend));
}
if (a.x1 > b.x1) { // Something visible on the right
result.push_back(Rect(b.x1, ystart, a.x1, yend));
}
}
return result;
}
上面的函数给定两个矩形A和B,返回一个矩形向量,结果为A-B。这个向量可能是空的(B 覆盖A)或者可能有一到四个矩形(四个是当B 严格包含在A 中时,因此结果将是一个带有矩形孔的矩形)。
使用此函数,您可以轻松计算new-old 和old-new 面积。
请注意,上述代码中使用的坐标模式假定基于点的坐标系(不是基于像素的坐标系):
请注意,在上图中,矩形的水平 X 坐标从 0 到 W(不是 W-1),垂直 Y 坐标从 0 到 H(而不是 H-1)。
像素只是区域 1 坐标为(x, y)-(x+1, y+1) 的矩形;这个像素的中心是(x+0.5, y+0.5)。带有x0==x1 或y0==y1 的矩形是空的。
另请注意,代码假定(并返回)非空方向的矩形,即x0<x1 && y0<y1。
这种将像素坐标概念与点坐标概念分开的方法简化了很多像素数学运算:例如矩形区域是width*height 而不是(width-1)*(height-1)。
一个小程序来测试你的输入案例如下
void print_result(const char *name,
const std::vector<Rect>& rects)
{
printf("Result '%s' (%i rects):\n", name, int(rects.size()));
for (int i=0,n=rects.size(); i<n; i++)
{
printf(" %i) (%i, %i) - (%i, %i)\n",
i+1,
rects[i].x0, rects[i].y0,
rects[i].x1, rects[i].y1);
}
}
int main()
{
Rect A(1, 1, 6, 6);
Rect B(3, 2, 8, 7);
print_result("A-B", subtract(A, B));
print_result("B-A", subtract(B, A));
return 0;
}
这个程序的输出是
Result 'A-B' (2 rects):
1) (1, 1) - (6, 2)
2) (1, 2) - (3, 6)
Result 'B-A' (2 rects):
1) (3, 6) - (8, 7)
2) (6, 2) - (8, 6)