2011. 8. 6. 15:48

2D 좌표에서 사각형 맵을 사용한다면 마름모 외각의 좌표를 쓸 일이 많습니다.

기준 좌표에서 마름모로 퍼지는 영역을 체크해야 하는 일이 많기 때문이죠.

 

로봇 대전에서 볼 수 있는 이것이 바로 마름모 영역입니다.

로봇 대전 알파 외전

 

이 마름모 영역을 구하려면 마름모의 외곽 좌표를 알아야 하죠.

 

 

1. 2D사각형 맵

2D사각형 맵은 아래와 같이 구성됩니다.

한칸은 픽셀이 될 수 도 있고 논리적인 1칸이 될 수도 있습니다.

 

 

우리가 구해야 할 값은 A를 기준으로 하는 범위입니다.

 

B0는 Y - 1, B1은 X + 1 입니다.

 

그러면 C3은 어떻게 구할까요? A에 X와 Y가 1씩 더해주면 됩니다.

 

그러면 D4는?

그렇습니다. 3번째 칸부터는 기존 방식으로 외곽선 좌표를 구할 수가 없습니다.

 

 

방법이야 몇 가지 있습니다만 무식한 방법으로는

1) 모든 셀을 검사한 후

2) 기준 좌표와 거리를 계산해서(대각선 거리)

3) 일정 거리 안에 있으면 범위 안이라고 판단하는 방법이 있습니다.

 

모든 셀을 검사해야 하니 당연히 부하가 심한 방법입니다 ㅎㅎㅎ

 

 

2. 필요한 좌표만 뽑아내기

당연히 모든 칸을 계산하거나 할 필요는 없습니다.

꼭짓점(D0, D3, D6, D9) 의 값을 구한 후 각 대각선으로 가면서 각 꼭짓점 직전까지 구하면 쉽게 구할 수 있습니다.

 

그림으로 봅시다.

 

D0를 구하고, Y+1, X-1 하여 D11과 D10을 구합니다.

이 방법으로 다른 꼭지점에서부터 대각선 좌표를 구할 수 있습니다.

 

 

3. 코드화

코드화를 만들어 봅시다.

 

.NET으로 만듭니다.

예제는 WPF입니다.

 

3-1. 하나의 꼭짓점과 선 좌표

D0를 구한 후 D11과 D10을 구하는 것을 먼저 구해 봅시다

//외곽선 좌표
List<Point> pointRange = new List<Point>();

//기준 좌표에서부터 거리
int nRange = 3;

for (int i = 0; i < nRange; ++i)
{
    //1.위에서 왼쪽으로
    pointRange.Add(new Point(5 - i, 4 - nRange + i));
}

 

7번 줄 : 기준 좌표로부터 3칸(0~2) 떨어져 있는 좌표만큼 찾습니다.

 

10번 줄 : Point(5, 4)가 기준점의 좌표입니다.

Point(5, 4 - 3) 하면 D0의 값이 나옵니다.

Point(5 - 1, 4 - 3 + 1) 하면 D11,

Point(5 - 2, 4 - 3 + 2) 하면 D10 의 좌표가 나옵니다.

 

3-2. 함수화

이제 파라미터를 받아서 E0에서도 쓸 수 있도록 함수로 만들어 봅시다.

/// <summary>
/// 해당 중심점을 기준으로 마름모 칸에 해당하는 외곽선의 좌표를 구해 리턴합니다.
/// 마이너스(-)값도 출력 됩니다.
/// </summary>
/// <param name="nRange">기준으로 부터 거리</param>
/// <param name="nCenterX">기준X</param>
/// <param name="nCenterY">기준Y</param>
/// <returns>외곽선 좌표 리스트</returns>
private List<Point> DiamondTile(int nRange, int nCenterX, int nCenterY)
{
    //외곽선 좌표
    List<Point> pointRange = new ListList<Point>();

    for (int i = 0; i < nRange; ++i)
    {
        //1.위에서 왼쪽으로
        pointRange.Add(new Point(nCenterX - i, nCenterY - nRange + i));
    }

    return pointRange;
}

 

17번 줄 : D10과 D11의 값을 구하기 위해 i값으로 가중을 해줍니다.

 

3-3. 나머지 꼭짓점에서 선 좌표 구하기

이제 위와 같은 방법으로 다른 꼭짓점들의 좌표를 구할 수 있습니다.

for (int i = 0; i < nRange; ++i)
{
    //1.위에서 왼쪽으로
    pointRange.Add(new Point(nCenterX - i, nCenterY - nRange + i));

    //2.왼쪽에서 아래쪽으로
    pointRange.Add(new Point(nCenterX - nRange + i, nCenterY + i));

    //3.아래에서 오른쪽으로
    pointRange.Add(new Point(nCenterX + i, nCenterY + nRange - i));

    //4.오른쪽에서 윗쪽으로
    pointRange.Add(new Point(nCenterX + nRange - i, nCenterY - i));
}

 

4번 줄 : D0 -> D10

 

7번 줄 : D9 -> D7

 

10번 줄 : D6 -> D4

 

13번 줄 : D3 -> D1 

 

 

이 함수는 최소/최대 범위를 체크하지 않으므로

맵 밖으로 나갔는지 여부는 확인할 수 없습니다.

 

 

4. 테스트

셈플 코드 : github - dang-gun/DotNetSamples/RhombusOutlinePoint

 

 

 

마무리

만들어 놓고나면 별게 아닌데 만들때 고생하는 함수입니다.