我有以下问题。假设您在平面上有一大堆曼哈顿多边形(它们的边与x轴或y轴平行)。我需要找到一个比一些值delta更接近的多边形。问题是如何以最有效的方式实现这一点,因为这个多边形的数量非常大。如果您能给我一个实施解决方案的参考,我将很高兴,这将很容易适应我的情况。
答案 0 :(得分:1)
首先想到的是扫描和修剪算法(也称为排序和扫描)。
基本上,您首先要找出每个轴上每个形状的“边界”。对于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.
};
创建这些边界的两个数组,一个用于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)一对形状。