모든 타일을 반복하거나 건너 뛰지 않고 선으로 교차하는 타일 찾기


10

나는 며칠 동안이 문제를 쳐다보고있다. 문제를 시각화하는 데 도움이되도록이 그래픽을 조작했습니다. 여기에 이미지 설명을 입력하십시오 (그래프에서 선이 [1, 1], [1, 2], [2, 2], [2, 3]과 교차하고 [ 3,3])

선을 따라 각 격자 공간으로 이동하여 격자 공간의 재질이 단단한 지 확인하고 싶습니다. 나는 이미 관련된 수학을 알고 있다고 생각하지만 아직 함께 묶을 수는 없습니다. 경로 찾기 알고리즘을 통해 경로를 찾은 후 이것을 사용하여 가시선을 테스트하고 노드를 제거합니다. 내 에이전트는 솔리드 블록을 통해 볼 수 없으므로 하나를 통과 할 수 없으므로 노드가 경로에서 제거되지 않기 때문에 코너를 탐색하려면 필요합니다.

따라서 교차하는 각 그리드 공간으로 라인을 따라 이동하는 알고리즘이 필요합니다. 어떤 아이디어?

Bresenham과 같은 많은 일반적인 알고리즘과 선을 따라 미리 정의 된 간격으로 단계를 밟는 알고리즘을 살펴 보았습니다 (불행히도이 방법은 타일이 단계 크기보다 작은 웨지와 교차하는 경우 타일을 건너 뜁니다).

현재 화이트 보드에 많은 floor () 및 ceil () 함수를 사용하고 있지만 지나치게 복잡 해져서 속도가 느려질 수 있습니다.


실제 라인 박스 교차를 테스트하는 방법을 이미 알고 있습니까? 그냥 물어 보면 대답과 관련이 있습니다.
TravisG

의 중복 가능성 내가 부동 소수점 엔드 포인트 Bresenham의 라인 알고리즘을 일반화 어떻게해야합니까? (질문은 실제로 Bresenham에 관한 것이 아닙니다)
sam hocevar

답변:


6

시작 블록을 알고 있다면 (X 지점을 알고 블록 목록에 블록 [0,1]을 포함시키지 않기 때문에 시작 블록도 알고 있다고 가정합니다) Bresenham의 알고리즘을 반드시 사용해야한다고 생각합니다. 당신은 그것을 썼다.

이 문제에 적합한 알고리즘입니다. 또한 방식으로 작성 될 수 있으며 정수로만 계산됩니다. 웹에서 많은 구현을 찾을 수 있습니다.

편집하다:

죄송합니다. Bresenham이 모든 블록을 찾지 못할 것입니다. 그래서 더 나은 해결책을 찾았습니다 . C ++로 작성된 코드도 있지만 이해하기 어렵지 않아야한다고 생각합니다. :)


1
내가 Bresenham 알고리즘을 살펴본 이유는 순전히 Wikipedia의 이미지 때문이었습니다. ( en.wikipedia.org/wiki/File:Bresenham.svg ) 선은 간신히 보이지만 일부 음영 처리되지 않은 사각형을 가로채는 것을 볼 수 있습니다. 슬라이스가 얼마나 작은 지에 관계없이 모든 타일 을 감지 할 수있는 것이 필요합니다 . 편집 : 어쨌든 bresenham의 오해가있는 것 같습니다. 나는 그것을 뒤집어 야합니다-첫 번째와 마지막 점이 있으며 줄거리가 가장 좋은 선이 아니라 교차하는 타일이 필요합니다.
Suds

@JustSuds : 게시물 업데이트를 확인하십시오.
zacharmarz

이봐! 화이트 보드에있는 것과 거의 일치합니다. 감사합니다. 이제 시스템이 구현되어 작동합니다. :-)
Suds

Bresenham의 알고리즘이 질문에 대답하지 않으므로 알고리즘의 일부를 제거 할 수 있습니까? 걱정하지 마십시오. 답변의 편집 기록에 남아 있습니다.
제니스

1

허용되는 답변이 연결되는 예제의 코드는 완벽하게 대각선을 조정해야합니다. 다음 은 Qt (C ++ 및 QML)로 작성된 완벽한 데모 응용 프로그램입니다.

그리드 라인 교차

관련 C ++ 코드 :

void rayCast()
{
    if (!isComponentComplete())
        return;

    mTiles.clear();
    mTiles.fill(QColor::fromRgb(255, 222, 173), mSizeInTiles.width() * mSizeInTiles.height());

    const QPoint startTile = startTilePos();
    const QPoint endTile = endTilePos();
    // http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
    int x0 = startTile.x();
    int y0 = startTile.y();
    int x1 = endTile.x();
    int y1 = endTile.y();

    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    int x = x0;
    int y = y0;
    int n = 1 + dx + dy;
    int x_inc = (x1 > x0) ? 1 : -1;
    int y_inc = (y1 > y0) ? 1 : -1;
    int error = dx - dy;
    dx *= 2;
    dy *= 2;

    for (; n > 0; --n)
    {
        visit(x, y);

        if (error > 0)
        {
            x += x_inc;
            error -= dy;
        }
        else if (error < 0)
        {
            y += y_inc;
            error += dx;
        }
        else if (error == 0) {
            // Ensure that perfectly diagonal lines don't take up more tiles than necessary.
            // http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html?showComment=1281448902099#c3785285092830049685
            x += x_inc;
            y += y_inc;
            error -= dy;
            error += dx;
            --n;
        }
    }

    update();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.