给定一个在某个 X[-inf, +inf] 轴上的坐标平面和一个标称 Y[-inf, +inf] 轴,如果两个点在水平轴上的坐标(我们选择 X)可以说是垂直对齐的是平等的。如果它们在垂直轴 (Y) 上的坐标相等,则可以说它们处于水平对齐状态。
一个矩形可以用两对坐标 (x1, y1) 和 (x2, y2) 来描述,使得 x1 <= x2,并且 y1 <= y2。(如果您的配对混合在一起,您实际上可以重新排列它们以使用这种格式 - 它会让您的生活更轻松。)
当且仅当 r1.x1 >= r2.x1、r1.y1 >= r2.y1、r1.x2 <= r2.x2 和 r1 时,可以说一个矩形 (r1) 位于另一个矩形 (r2) 内。 y2 <= r2.y2 都成立。请注意,无论您在哪个象限,或者您的轴在哪个方向运行,这都是正确的。
当且仅当 r1.x1 和 r1.x2 都在范围之外 (r2.x1, r2.x2) 并且 r1.y1 和 r1.y2 都在范围之外时,可以说一个矩形 (r1) 位于另一个矩形 (r2) 之外超出范围 (r2.y1, r2.y2)。请注意,这包括 r2 在 INSIDE r1 的情况。
一个矩形 (r1) 可以说是与另一个矩形 (r2) 分开的,当且仅当它在那个矩形之外,并且那个矩形不在它里面。(即:r1 OUTSIDE r2 && NOT r2 INSIDE r1)
一个矩形 (r1) 可以说与另一个矩形 (r2) 重叠当且仅当它既不在该矩形的内部也不在该矩形的外部。(或者,您可以选择声称完全在另一个矩形内的矩形是有效重叠,并说 OVERLAP = !SEPARATE。取决于您的应用程序。)
矩形的对齐要困难得多。SAME EXACT size 的 Rectangles 可以说是和 points 一样对齐(使用每个矩形的 (x1, y1) 作为你的参考点。对于 Rectangles of Differing size,我建议你使用中心点作为参考:如果 (r1.x1+r1.x2)/2 = (r2.x1+r2.x2)/2,则矩形垂直对齐,如果 (r1.y1+r1.y2)/2 = (r2.y1 则水平对齐+r2.y2)/2。
我会编写一个包含这些规则的类,并使用它来检查每个动作,使用三个矩形——你提到的两个,第三个是边界框。
CLASS rectangle
x1
x2
y1
y2
CONSTRUCT(xx1, yy1, xx2, yy2):
Ensure xx1 <= xx2 and yy1 <= yy2 - swap them if you like
x1 = xx1, y1 = yy1, x2 = xx2, y2 = yy2
IS_INSIDE(rectangle r2):
IF r2.x1<=x1 && r2.y1<=y1 && y2 <= r2.y2 && x2 <= r2.x2:
RETURN TRUE
RETURN FALSE
IS_OUTSIDE(rectangle r2):
IF r2.x1 <= x1 <= r2.x2 || r2.x1 <= x2 <= r2.x2 || r2.y1 <= y1 <= r2.y2 || r2.y1 <= y2 <= r2.y2 :
RETURN FALSE
RETURN TRUE
IS_SEPARATE(rectangle r2):
IF IS_OUTSIDE(r2) && ! r2.IS_INSIDE(me):
RETURN TRUE
RETURN FALSE
IS_OVERLAPPED(rectangle r2):
IF ! IS_OUTSIDE(r2) && ! IS_INSIDE(r2):
RETURN TRUE
RETURN FALSE
IS_VERTICALLY_ALIGNED(rectangle r2):
IF (x1+x2)/2 = (r2.x1+r2.x2)/2:
RETURN TRUE
RETURN FALSE
IS_HORIZONTALLY_ALIGNED(rectangle r2):
IF (y1+y2)/2 = (r2.y1+r2.y2)/2:
RETURN TRUE
RETURN FALSE
然后你可以写一个非常简单的函数来查看r2是否被有效放置,假设r2是可移动的矩形,r1是固定的,box是一个未显示的矩形,代表画布的边界框:
IS_VALID_PLACEMENT(r2, r1, box):
//In the bounding box
IF r2.IS_OUTSIDE(box):
RETURN FALSE
//Aligned with r1
IF ! r2.IS_VERTICALLY_ALIGNED(r1) && ! r2.IS_HORIZONTALLY_ALIGNED(r1):
RETURN FALSE
//Not overlapping r1
IF ! r2.IS_SEPARATE(r1):
RETURN FALSE
RETURN TRUE
每次盒子移动时都运行它。如果返回 false,则撤消移动,或使用边界逻辑进行邻接。
编辑
我正在重读你的问题,我注意到你对垂直对齐的定义。完全可行:
IS_VERTICALLY_ALIGNED(rectangle r2):
IF x1 <= r2.x1 <= r2.x2 <= x2 || r2.x1 <= x1 <= x2 <= r2.x2:
RETURN TRUE
RETURN FALSE
IS_HORIZONTALLY_ALIGNED(rectangle r2):
IF y1 <= r2.y1 <= r2.y2 <= y2 || r2.y1 <= y1 <= y2 <= r2.y2:
RETURN TRUE
RETURN FALSE