Онлайн-метод обхода кривой Гильберта

Учитывая двумерную область с размерами NxN, где N - степень двойки, мне интересно, как пройти каждую точку, начиная с (0, 0), вдоль дискретного представления кривой Гильберта.

Например, для области 2x2 он будет проходить в порядке (0, 0), (1, 0), (1, 1), (0, 1), но пути будут становиться все более сложными с увеличением размера. Как следует, учитывая размер области и координаты текущей точки, вычислить следующую точку в последовательности?

Википедия дает следующий код для преобразования из (x, y) в индекс вдоль кривой Гильберта:

//convert (x,y) to d
int xy2d (int n, int x, int y) {
    int rx, ry, s, d=0;
    for (s=n/2; s>0; s/=2) {
        rx = (x & s) > 0;
        ry = (y & s) > 0;
        d += s * s * ((3 * rx) ^ ry);
        rot(n, &x, &y, rx, ry);
    }
    return d;
}

//convert d to (x,y)
void d2xy(int n, int d, int *x, int *y) {
    int rx, ry, s, t=d;
    *x = *y = 0;
    for (s=1; s<n; s*=2) {
        rx = 1 & (t/2);
        ry = 1 & (t ^ rx);
        rot(s, x, y, rx, ry);
        *x += s * rx;
        *y += s * ry;
        t /= 4;
    }
}

//rotate/flip a quadrant appropriately
void rot(int n, int *x, int *y, int rx, int ry) {
    if (ry == 0) {
        if (rx == 1) {
            *x = n-1 - *x;
            *y = n-1 - *y;
        }

        //Swap x and y
        int t  = *x;
        *x = *y;
        *y = t;
    }
}

Таким образом, я мог преобразовать текущую точку в индекс, увеличить ее, а затем преобразовать обратно в координаты. Меня интересует, есть ли лучший способ сделать это, когда индекс только увеличивается или уменьшается на 1, например, алгоритм сублинейного времени по отношению к размерам области. Пахнет отраженным двоичным кодом, но я не знаю, как это сделать.

0 ответов

Другие вопросы по тегам