首先想到的是sweep and prune算法(也称为sort and sweep)。
基本上,您首先要找出每个形状沿每个轴的“边界”。对于 x 轴,这些将是形状上最左边和最右边的点。对于 y 轴,最高和最低。
假设您有一个看起来像这样的绑定结构:
struct Bound
{
float value; // The value of the bound, ie, the x or y coordinate.
bool isLower; // True for a lower bound (leftmost point or bottommost point).
int shapeIndex; // The index (into your array of shapes) of the shape this bound is on.
};
为这些 Bounds 创建两个数组,一个用于 x 轴,一个用于 y 轴。
Bound xBounds* = new Bound[2 * numberOfShapes];
Bound yBounds* = new Bound[2 * numberOfShapes];
您还需要另外两个数组。一个数组,用于跟踪每对形状在多少个轴上彼此接近,以及一个候选对数组。
int closeAxes* = new int[numberOfShapes * numberOfShapes];
for (int i = 0; i < numberOfShapes * numberOfShapes; i++)
CloseAxes[i] = 0;
struct Pair
{
int shapeIndexA;
int shapeIndexB;
};
Pair candidatePairs* = new Pair[numberOfShapes * numberOfShape];
int numberOfPairs = 0;
遍历您的形状列表并适当地填充数组,但有一个警告:
由于您正在检查接近度而不是相交,因此将 delta 添加到每个上限。
然后使用您喜欢的任何算法按值对每个数组进行排序。
接下来,执行以下操作(并对 Y 轴重复):
for (int i = 0; i + 1 < 2 * numberOfShapes; i++)
{
if (xBounds[i].isLower && xBounds[i + 1].isLower)
{
unsigned int L = xBounds[i].shapeIndex;
unsigned int R = xBounds[i + 1].shapeIndex;
closeAxes[L + R * numberOfShapes]++;
closeAxes[R + L * numberOfShapes]++;
if (closeAxes[L + R * numberOfShapes] == 2 ||
closeAxes[R + L * numberOfShapes] == 2)
{
candidatePairs[numberOfPairs].shapeIndexA = L;
candidatePairs[numberOfPairs].shapeIndexB = R;
numberOfPairs++;
}
}
}
所有候选对在每个轴上的距离都小于 delta。现在只需检查每个候选对以确保它们实际上小于 delta。我现在不会详细说明如何做到这一点,因为,好吧,我还没有真正考虑过,但希望我的回答至少能让你开始。我想您可以只检查每对线段并找到最短的 x 或 y 距离,但我确信有一种更有效的方法来执行“窄相”步骤。
显然,该算法的实际实现可能要复杂得多。我的目标是使解释清晰而简短,而不是优雅。根据形状的布局和使用的排序算法,就效率而言,单次运行大约在 O(n) 和 O(n log n) 之间,而不是 O(n^2) 来检查每个一对形状。