拓扑层分离算法

时间:2012-02-01 18:57:35

标签: c++ polygon

我有以下问题。假设您在平面上有一大堆曼哈顿多边形(它们的边与x轴或y轴平行)。我需要找到一个比一些值delta更接近的多边形。问题是如何以最有效的方式实现这一点,因为这个多边形的数量非常大。如果您能给我一个实施解决方案的参考,我将很高兴,这将很容易适应我的情况。

1 个答案:

答案 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)一对形状。