我正在寻找一种算法,它采用由(xa1,ya1,xa2,ya2)和(xb1,yb1,xb2,yb2)定义的两个矩形,检查它们是否可以组合成一个矩形,如果它们可以,返回新的矩形。一个例子:
xa1=0,ya1=0,xa2=320,ya2=119
xb1=0,yb1=120,xb2=320,yb2=239
这两个矩形可以组合成以下矩形:
xc1=0,yc1=0,xc2=320,yc2=240
你会如何实现这样的算法?谢谢!
答案 0 :(得分:8)
我将绘制以下图片并将其写为算法:
...xxxxxxx xxxxxxx....
. x . x x . x .
. x . x x . x .
...xxxxxxx xxxxxxx....
xxxxxxx .......
x x . .
x.....x xxxxxxx
xxxxxxx x.....x
. . x x
....... xxxxxxx
..........
. .
. xxxx .
. x x .
. x x .
. xxxx .
..........
xxxxxxxxxxxxxx
x x
x ....... x
x . . x
x . . x
x ....... x
x x
xxxxxxxxxxxxxx
检查角落情况!
答案 1 :(得分:0)
当且仅当一个矩形的一对相对边与另一个矩形的一对相对边重叠时,它们可以组合。通过重叠,我的意思是它们是平行的并且包含至少一个共同点。
你应该能够找出代码;)
编辑:哦,我忘了提到两个矩形完全重叠的情况。这也不应该太难以检查。
答案 2 :(得分:0)
两个矩形必须相交。边界矩形的角落必须全部落在现有角落上。
这两个条件是必要和充分的。显然矩形必须相交,并且,因为您不能仅使用2个交叉矩形创建非角落空白区域,所以边界角必须落在现有角上。
return r1.Intersects(r2) and r1.BoundingRectangleWith(r2).Corners.IsSubsetOf(r1.Corners.Union(r2.Corners))
实施Intersects
,BoundingRectangleWith
,Corners
和IsSubsetOf
非常简单。然后,您可以内联它们以获得更好的性能,但这将是一堆难以理解的比较。
修改的
您的一条评论表明您不希望矩形重叠,只是触摸。在这种情况下,您只需要在一个轴(即X或Y)上检查矩形的范围是否相等,而在另一个轴上检查范围是否接触。如果其边界的中位数有2次出现,则触摸两个范围。请注意,如果您希望right = 1触摸left = 2,则需要将1添加到天花板边界。
答案 3 :(得分:0)
经过多次摆弄后,我有点计算出你想要的东西。请注意,“严格边界框”仍然存在一些争议:原始问题中的示例不符合您提供的描述:
但是,如果边界框恰好是两个矩形组合的大小,则只应组合矩形,即边界矩形的面积必须与两个源矩形的面积大小完全相同。如果rect 1的区域是a1,rect2的区域是a2,并且bounding rect的区域是a3,那么a1 + a2 = a3。
这个实现应该给你很多想法,我相信你知道怎么写
r.area() == a.area() + b.area()
如果你真的想要那个。
// Final proposal: combine adjacent rectangles,
// if they are 'flush': almost touching
#include <iostream>
struct R
{
int x1,y1,x2,y2;
int height() const { return y2-y1; }
int width() const { return y2-y1; }
void normalize()
{
if (x1>x2) std::swap(x1,x2);
if (y1>y2) std::swap(y1,y2);
}
/*
* adjacent: return whether two rectangles
* are adjacent; the tolerance in pixels
* allow you to specify the gap:
* tolerance = 0: require at least one pixel overlap
* tolerance = 1: accepts 'flush' adjacent neighbours
* Negative tolerance require more overlap;
* tolerance > 1 allows gaps between rects;
*/
bool adjacent(R const& other, int tolerance=1) const
{
return !( (other.x1 - x2) > tolerance
|| (x1 - other.x2) > tolerance
|| (other.y1 - y2) > tolerance
|| (y1 - other.y2) > tolerance);
}
};
/*
* tolerance: see R::adjacent()
*
* strict: only allow strict ('pure') combinations of rects
*/
R combined(R const& a, R const& b, int tolerance=1, bool strict=false)
{
if (!a.adjacent(b, tolerance))
throw "combined(a,b): a and b don't satisfy adjacency requirements (are the coords normalized?)";
R r = { min(a.x1, b.x1), 1,1,1};
r.x1 = min(a.x1, b.x1);
r.y1 = min(a.y1, b.y1);
r.x2 = max(a.x2, b.x2);
r.y2 = max(a.y2, b.y2);
if (!strict)
return r;
if ( (r.height() <= max(a.height(), b.height()))
&& (r.width () <= max(a.width (), b.width ())) )
return r;
else
throw "combined(a,b): strict combination not available";
}
std::ostream& operator<<(std::ostream &os, R const& r)
{
return os << '(' << r.x1 << "," << r.y1 << ")-(" << r.x2 << ',' << r.y2 << ')';
}
int main()
{
const int tolerance = 1;
{
std::cout << "sample from original question" << std::endl;
R a = { 0, 0, 320, 119 }; /* a.normalize(); */
R b = { 0, 120, 320, 239 }; /* b.normalize(); */
std::cout << "a: " << a << "\t b: " << b << std::endl;
std::cout << "r: " << combined(a,b, tolerance) << std::endl;
}
{
std::cout << "sample from the comment" << std::endl;
R a = { 0, 0, 1, 320 }; /* a.normalize(); */
R b = { 0, 0, 2, 320 }; /* b.normalize(); */
std::cout << "a: " << a << "\t b: " << b << std::endl;
// NOTE: strict mode
std::cout << "r: " << combined(a,b, tolerance, true) << std::endl;
}
}
sample from original question
a: (0,0)-(320,119) b: (0,120)-(320,239)
r: (0,0)-(320,239)
sample from the comment
a: (0,0)-(1,320) b: (0,0)-(2,320)
r: (0,0)-(2,320)