폴리곤의 구성 좌표가 시계방향인지 반시계방향인지 검사하기

폴리곤이 오목한지 볼록한지에 대한 각각의 경에 대해서, 좌표가 시계방향으로 되어 있는지, 반시계 방향으로 되어 있는지를 검사하기 위한 방법입니다. GIS에서 폴리곤 도형에 대해 시계방향인지 반시계방향인지에 따라 폴리곤에 대한 구멍(Hole)인지의 여부를 결정짓는 경우가 있습니다. 이외에 폴리곤의 앞면인지 뒷면인지의 여부도 시계방향인지의 여부에 따라 결정됩니다.

먼저 폴리곤의 구성하는 좌표의 개수가 N개라고 하고, 구성 좌표를 아래처럼 표기합니다.

사용자 삽입 이미지

볼록한 폴리곤에 대해서 좌표의 방향에 대한 간단한 검사는 인접한 좌표들이 이루는 선분(벡터)에 대한 외적(Cross Product)을 통해 가능합니다. 만약에 외적이 양수이면 수직벡터가 폴리곤이 이루는 평면(z축이 평면의 위쪽으로 향한다고 가정) 윗 방향이고, 음수이면 평면의 안쪽 즉 평면에 대해 아래 방향으로 향합니다.

사용자 삽입 이미지
오목한 폴리곤의 경우는 폴리곤의 면적을 계산함으로써 알 수가 있습니다. 면적을 계산하는 공식은 다음과 같습니다. (왜 이렇게 되는지는 블로그의 다른 글을 통해 곧 소개 하겠습니다)

사용자 삽입 이미지
위의 값이 양수이면 폴리곤의 구성 좌표의 구성 순서가 시계 반대 방향이고, 음수이면 시계 방향임을 나타냅니다.

이제 그렇다면, 뒤집어서…. 폴리곤이 오목한지 볼록한지는 어떻게 알 수 있을까요? 그것은 볼록한 폴리곤을 이루는 인접한 선분 벡터들은 모두 같은 부호이지만, 오목한 폴리곤의 경우는 부호가 섞여 있다는 것으로 알 수 있습니다.

평면과 선의 교차점 구하기

하나의 평면에 대해서 2가지의 평면공식이 도출되는데, 이 2가지 평면의 공식에 대해서.. 선과 평면에 대한 교차점을 구하는 방법에 대해서 논의해 보겠습니다. 이 자료는 1991년에 작성된 Paul Bourke(http://local.wasp.uwa.edu.au)님의 글을 좀더 알기 쉽게 풀어 쓴 글입니다.
사용자 삽입 이미지방법 1.

점 P는 평면 위의 임이의 점이고, N은 법선벡터이며 P3는 이미 알고 있는 평면상의 점이라고 하면 평면의 공식은 우리가 고등학교때 배운 평면의 방정식의 형태인, 다음처럼 기술됩니다.

사용자 삽입 이미지
평면을 수학적으로 기술했으니, 이제는 선에 대한 공식을 알아볼 차례입니다. 이제 앞에서 언급한 점 P를 평면과 선과의 교차점이라고 하면, 점 P는 선에 대한 점입니다. 그리고 선이 지나는 이미 알고 있는 2개의 점을 각각 P1, P2라고 하면 선에 대한 공식은 수학적으로 다음과 같습니다.

사용자 삽입 이미지
위에서 u는 선에 대한 기울기 값이 되겠지요. 이제.. 평면의 공식에서 P에 선의 공식을 대입할 수 있는 형태입니다. 대입해 보면 아래와 같습니다.

사용자 삽입 이미지
위의 식을 u에 대해서 전개해 보면 아래와 같은 공식이 됩니다.

사용자 삽입 이미지

이제 u값을 구했으니.. 이 u값을 선에 대한 공식에 대입하여 교차점 P를 구할 수 있습니다. 다음은 주의할 점입니다.

  • 만약 u에 대한 식에서 분모가 0이면, 주어진 선과 평면의 법선은 수직이라는 의미입니다. 즉, 이말은 평면과 선은 서로 만나지 않는다는 의미입니다.
  • 교점 P가 P1과 P2 사이에 있는지 검사해야한다면, u값이 0~1사이의 값인지 확인해 보면 됩니다.

방법 2.

이제 평면에 대한 공식으로, 고등학교때 배운 또 다른 형태는 다음과 같습니다.

사용자 삽입 이미지
(x,y,z)는 평면상의 점이고 (A,B,C)는 평면에 대한 법선벡터이며 D는 이 법선벡터의 길이값입니다. 이 형태의 평면방정식은 임이의 점에 대해서 위의 공식에 대입하여 그 값이 양수인경우 평면을 경계로 법선벡터가 향하는 부분에 존재하는 것이고, 음수인경우는 그 반대방향에 존재하는 것을 간단히 판단할 수 있습니다.

P1(x1,y1,z1)과 P2(x2,y2,z2)를 지나는 선에 대한 공식을 방법1에서의 선에 대한 공식… 다시 언급해 보면 아래와 같습니다.

사용자 삽입 이미지
위의 선 공식을 방법2에서의 평면의 공식에 대입해 보면 다음과 같은 형태로 전개됩니다.

사용자 삽입 이미지
위의 식을 u에 대해서 정리해 보면…

사용자 삽입 이미지
이제 u를 구했으니, 방법1과 마찬가지로 교점을 구할 수 있습니다. 이 방법에 대해 주의할 점은 방법 1과 동일합니다.

폴리곤에 높이를 줘 표현하기

폴리곤에 높이를 줘서 입체적으로 표현하는 방법을 소개합니다. 일단 주어진 폴리곤 데이터는 아래와 같다고 가정을 합니다. 실제 적용된 결과는 높이값을 가진 폴리곤 데이터의 입체화 를 살펴보시길 바랍니다.

이 폴리곤에 일정한 높이값을 주어 아래처럼 표현하는 예를 통해 설명하겠습니다.

높이값을 주어 위의 그림처럼 표현하기 위해 옆면과 윗면을 높이값을 이용해 그려준 것 뿐입니다. 매우 간단하지요.. 끝?

하지만 이렇게 매우 단순하지 않습니다. 처음 폴리곤은 4각형이므로 옆면이 모두 4개인데, 이 4개의 옆면을 우리가 바라보는 시선 거리 중 긴것 순서대로 그려줘야 입체적으로 보입니다. 하지만 이것도 문제가 있습니다. 즉, 4개의 면이 모두 보이는게 아니고, 위의 경우는 딱 2개만 보입니다. 즉, 속도 효율성을 위해서 보이는 옆면만을 그리되, 그리는 순서는 시선의 거리가 긴것을 먼저 그려야 합니다. 시선의 거리가 길다라는 의미는 쉽게 말해.. 멀리 있는 옆면을 먼저 그려야한다는 것입니다.

결국 절차는 아래와 같습니다.

  1. 폴리곤을 구성하는 옆면들 중에 보이는 옆면만을 골라 낸다.
  2. 골라낸 옆면 중에 멀리 있는 것부터 순서대로 그린다.
  3. 마지막으로 윗면을 그린다.

먼저 옆면중에서 보이는 면만을 골라 내는 방법은.. 일단 시선축이라는 것을 정의해야 합니다. 시선축은 폴리곤을 구성하는 좌표 중에서 가장 작은 y값을 가진 좌표를 지나는 x축과 평행한 선분입니다.

위의 예 같은 경우는 아래의 그림처럼 시선축(빨간색 선)을 정의할 수 있습니다.

이제 다음으로 폴리곤을 구성하는 각 선분(위의 예는 4개의 선분)에 대해 그 선분의 중점과 시선축과 수직선을 그려 봅니다. 이 수직선을 시선방향선이라고 하겠습니다. 아래의 그림이 폴리곤을 구성하는 하나의 선분(빨간색)의 중심점에서 시선축으로 시선방향선을 그려본 것인데.. 폴리곤을 구성하는 4개의 선분 중에서 2개와 교차하는 것을 알 수 있습니다.

하지만 여기서 중요한 예외 사항이 있는데.. 그것은 처음 기준이 되는 폴리곤을 구성하는 선분과의 중점과 시선축과의 거리(SL)이 선분을 구성하는 시작점이나 끝점과 시선축과의 거리보다 작다면 시선방향선과 교차하지 않는다고 가정을 합니다. 결과적으로 위의 경우는 시선방향선이 2개의 선분과 만나지만 1개만 만나는 것이 됩니다.

아래는 나머지 3개의 선분에 대한 시선 방향선을 표시한 그림들입니다.

시선방향선과 만나는 선분이 2개인 경우
시선방향선과 만나는 선분이 2개인 경우
시선방향선과 만나는 선분이 1개인 경우(예외로 인해 1개의 교차점은 제외)

이를 토대로, 유추를 해보면.. 교점의 수가 홀수인 경우가 보이는 옆면이고 짝수인 경우는 않보이는 옆면이라는 것을 알 수 있습니다.

이제 보이는 옆면을 고르는 것은 끝났고, 두번째 절차인 골라낸 옆면 중에 멀리는 있는 것부터 그리는 것은 골라낸 옆면에 대해 거리값, 위의 설명에서 SL의 값을 이용해 내림차순으로 정렬하여 정렬된 순서대로 옆면을 그리면 됩니다.

그리고 마지막 세번째 절차는 단순히 기존의 폴리곤을 y축으로 높이 값만큼 올려 그려주기만 하면 됩니다.

이해가 되셨는지 모르겠습니다. 이해가 되지 않는 부분에 대해서는 댓글을 통해 물어보시길 바랍니다.

선과 점 사이의 최소 거리 구하기

원문은 http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ 입니다.

지금 진행하고 있는 프로젝트에서 필요한 알고리즘인데, 어디 이미 구현된 소스 코드 없나… 찾다가 발견한것입니다. 찾고보니, 무척 오래전에 봤던 글이네요. 그런데 그때는 소스 코드를 제공하지 않았는데… 여하튼, 다시 복습하는 겸해서 번역해 올립니다. 예전과 다르게 그림도 깔끔해서 그 그림을 그대로 올리겠습니다. 물론 변역이기는 하지만, 나름대로 내용을 보충해서 올렸습니다. 내용 시작합니다~

P1(x1, y1)과 P2(x2, y2)를 지나는 선분의 공식은 아래와 같다.

P = P1 + u(P2P1)

점 P3(x3, y3)는 P1과 P2를 지나는 선분에 인접한 점이다. P3를 선분까지 수직으로 연장한 길이가 바로 우리가 구하고자 하는 값, 즉 최소 거리이다. 수직으로 연장해서 만나는 점을 P라고 하자. 즉, P는 선분 상의 점이 되겠다. 그렇다면, 벡터P3->P와 벡터 P2->P1를 정의할 수 있을 것이고, 이 두 벡터의 내적(Dot Product)는 0이다.

(P3P) dot (P2 P1) = 0

위의 식의 P에 처음에 언급한 선분의 식(P에 대한)을 대입해보면…

[P3P1 – u(P2P1)] dot (P2P1) = 0

위의 식을 u에 대해서 풀어보면,

이 u 값을 다시 처음의 선분의 방정식(P1과 P2를 지나는)에 대입해 교점P에 대한 x, y에 대해 풀어보면…

x = x1 + u(x2x1)
y = y2 + u(y2y1)

그렇다면… 이렇게 구한 P와 P3의 거리가 바로 우리가 구하고자 했던 최소 거리값이 된다.