| |
|
|
|
|
|
위의 그림에서 보는 것처럼 x축은 오른쪽으로 증가하고 y축은 아래쪽으로 증가하는 축에 대한 2점이 이루는 각도를 구하는 방법입니다. 각도는 60분법이며 편의상 0도 ~ 359.999999도로 산출됩니다. 딱히 말로써 설명드릴 것은 없을듯하고.. 코드 바로 나갑니다. 코드는 Java 입니다.
퍼포먼스를 고려한다면 9번 코드는 불필요합니다. -45도나 315도나 동일한 각도이니까요.
|
김형준(Dip2K)
2011/08/01 15:13
2011/08/01 15:13
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/733 |
|
|
|
|
|
|
|
|
|
김형준(Dip2K)
2011/02/13 06:34
2011/02/13 06:34
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/678 |
|
|
|
|
|
|
|
하나의 매우 큰 폴리곤의 일부를 화면상에서 확대할 경우에 렌더링 속도가 매우 느려질 수 있습니다. 예를 들어 한반도 전역을 아우르는 큰 하천 수계를 하나의 폴리곤으로 구성되어 있을 경우에.. 이 폴리곤을 화면상에 모두 그려지도록 할 경우 렌더링 속도에는 큰 문제가 없으나 이를 점차적으로 확대해 갈수록 그리기 속도는 점점 더... 그리고 훨씬 느려지게 됩니다.
이런 현상을 막기 위한 가장 좋은 방법은 화면 밖으로 벗어나는 대부분의 폴리곤 영역을 날려 버리는 것입니다. 바로 이때 적용할 수 있는 효율적인 알고리즘이 Sutherland-Hodgman Polygon Clipping 알고리즘입니다.
아래의 그림을 살펴보면 사각형 영역의 폴리곤과 잘려나갈 폴리곤이 존재합니다. 사각형 영역의 폴리곤은 모니터 영역이라고 생각하면 이 알고리즘을 실제 지도 엔진단에 적용할 때 이해가 쉽겠습니다.
위의 상황에서 Sutherland-Hodgman Polygon Clipping을 적용한 결과는 아래와 같습니다.
여기서 주의할 점은.. 이 알고리즘은 단지 폴리곤 렌더링에 적용할만하다 라는 점입니다. 이외의 부분에 대해서는 다른 알고리즘을 적용하기 바랍니다. 그 이유를 간단히 살펴보면 하나의 폴리곤을 화면 사각형에 대해 클리핑할때 다수의 폴리곤으로 분할되는 경우가 많은데 Sutherland-Hodgman Polygon Clipping 알고리즘은 다수의 폴리곤으로 분할하지 못하고 그 결과 역시 오직 하나의 폴리곤으로 클리핑하게 됩니다. 하지만... 그리기 위한 기능에서만큼은 그 어떠한 클리핑 알고리즘보다 빠른 퍼포먼스를 제공하므로 실제 적용할만한 알고리즘입니다.
이 알고리즘에 대한 소스 코드를 클래스화하여 제공합니다. 간단히 아래처럼 적용하면 원하는 결과를 얻을 수 있으리라 생각됩니다. 사용하는 좌표는 화면 좌표계입니다.
이 소스 코드의 활용과 위의 이미지에 대한 대한 데모에 대한 전체 코드는 아래를 통해 다운로드 받을 수 있습니다. 마우스 왼쪽 버튼으로 폴리곤을 구성하고 오른쪽 버튼을 누르면 클리핑된 폴리곤이 화면상에 표시됩니다.
|
김형준(Dip2K)
2010/01/05 16:16
2010/01/05 16:16
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/539 |
|
|
|
|
|
|
|
제목이 난해하니 먼저 그림부터 보였습니다. 주어진 선분이 있습니다. 이 선분의 시작점은 (X1, Y1)이고 끝점은 (X2, Y2)입니다. 그리고 주어진 좌표가 있으며 (a, b)입니다. 이 선분과 좌표에 대해서 거리 ln를 가지는 선분상의 좌표를 구하는 것에 대한 정리 포스트입니다. 즉, 위의 그림에서 파란색 점은 주어진 좌표이고 빨간 점을 구하겠다는 것입니다.
먼저 선분에 대한 아래와 같은 매개변수 방정식을 정합니다.
우리가 구해야할 점은 선분상의 점이니 위의 매개변수 방정식에서 x와 y가 바로 우리가 원하는 값입니다. 이 x와 y를 구하기 위해서는 매개변수 t를 구하면 됩니다. 아시겠지만 t가 주어진 선분위에 존재하려면 0~1사이의 값이여야 합니다. 이 값을 벗어나면 답은 없음... 입니다.
이 한가지 관계만 가지고는 않됩니다. 또 하나의 관계를 맺어줘야 합니다. 그 관계는 주어진 좌표(a, b)와 구하고자 하는 선분상의 점(x, y)사이의 거리가 값 ln이라는 사실로부터 다음과 같은 식을 얻을 수 있습니다.
이제 처음 선분에 대한 방정식을 위의 방정식의 x, y에 대입하고 t에 대해 정리를 하면 아래와 같은 t에 대한 2차 방정식이 도출되며 이 2차 방정식을 근의 공식을 통해 t를 구해 보면 다음과 같습니다.
이렇게 구한 t에 대해서 범위가 0~1사이 인지를 검사하고 이 범위에 있다면 이 t를 선분의 방정식에 대입하여 구한 (x, y)가 구하고자 하는 좌표입니다.
|
김형준(Dip2K)
2009/11/16 18:43
2009/11/16 18:43
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/527 |
|
|
|
|
|
|
|
이 얼마나 오랜만에 써보는 포스팅인지 모르겠습니다. 요즘 이러 저런 일로 바쁘다보니 블로그 관리에 매우 소홀했습니다. 이제 부터라도 짬짬히 시간을 내어.. 일상 업무에서 찾은 내용을 올리도록 노력 해야겠습니다. 해서... 알고보면 매우 간단한 내용이지만 포스팅 하나 올려봅니다.
오늘, 열심히 코드를 작성하던 중에.. 2차원에서 타원을 구성하는 좌표를 뽑아 낼 필요가 있었습니다. Needs는 하나의 타원과 또 다른 하나의 폴리곤을 하나의 도형으로 합(Union)하는 연산이 필요할듯 한데... 타원에 대한 정보는 단순히 중심점과 장반경 그리고 단반경만을 가지고 있음으로 폴리곤에 바로 합할 수 없는지라.. 일단 타원을 구성하는 정점을 이용하여 폴리곤으로 만들고.. 폴리곤과 폴리곤의 합 연산을 통해 원하는 결과를 얻고자 함이였습니다.
간단히 타원의 공식은 인터넷(http://en.wikipedia.org/wiki/Ellipse)을 통해 아래처럼 얻었습니다. 물론 프로그래밍에서 쉽게 사용할 수 있는 매개변수방정식으로 말입니다.
위의 식에서 Xc와 Yc는 타원의 중심입니다. 그리고 A와 B는 각각 X축과 Y축에 대한 타원의 반경이며 각각을 장축과 단축이라고 하겠습니다. 그리고 t는 0도에서 360도까지의 범위입니다. 물론 0도와 360도는 동일하므로 둘 중 하나는 포함되지 않아야 합니다. 마지막으로 ∅는 장축과 X축이 이루는 각도 입니다. 즉 ∅를 통해 기울어진 타원을 구성하는 좌표를 정의할 수가 있습니다. ∅에 대한 이해를 돕기 위해 아래 그림을 참고 하시기 바랍니다.
|
김형준(Dip2K)
2009/08/17 17:23
2009/08/17 17:23
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/497 |
Tracked from Adderall.
2009/11/23 21:53 x
제목 : Adderall.
Adderall side effects. Ordering adderall. Adderall....more
|
|
|
|
|
|
|
|
지형이라는 주제로 제작된 라스터(Raster)의 셀(Cell)에 기반한 분석 중 경사(Slope)와 향(Aspect) 분석은 중요한 자리를 차지하며, 이 경사와 향은 지형에 대한 분석 및 응용의 파라메터로 사용됩니다. 이 글은 개발 중인 지도 엔진의 확장 기능의 하나로써 경사와 향을 분석하는 것과 이 경사와 향을 분석하는 기능을 응용하여 다시 지형의 음영도(Hillshade)를 만드는 확장 기능에 대한 소개입니다. 여기서 확장 기능이란 지도 엔진과는 별개의 파일 단위로써 엔진에 플러그인하여 별도의 스레드를 통해 실행시킬 수 있는 외부의 확장 실행 단위 모듈입니다.
경사와 향 값을 분석하기 위해서는 분석 대상이 되는 지역에 대한 DEM 데이터가 필요합니다. 이 DEM의 라스터 데이터로써 아래와 같은 데이터를 사용하였습니다.
이 데이터는 김한국님이 운영하는 비지니스 GIS 커뮤니티(www.biz-gis.com)에서 내려 받은 데이터입니다. 그리고 위의 이미지를 포함해서 앞으로 나오는 지도 화면은 모두 오픈메이트(www.openmate.co.kr)의 개발한 맵 엔진으로 생성한 화면입니다. 위의 데이터를 통해 경사값과 향을 계산하기 전에 간단히 경사와 향이 무엇인지에 대해 언급하겠습니다.
경사(Slope)란 어떤 지점의 지반이 수평을 기준으로 몇도 정도 기울어져 있는가를 말하는 것으로 다음 그림을 통해 쉽게 이해할 수 있을 것입니다.
바로 저 세타 각도가 경사 기울기에 대한 각도로써 각이 클 수록 지반의 경사가 급하고 각이 0이면 평편한 지반임을 나타냅니다.
향(Aspect)이란 지반의 경사면이 어디를 향하고 있는지에 대한 것입니다. 만약 지반의 경사면이 북쪽을 향하고 있다면 0도, 동쪽은 90도, 남쪽은 180도 그리고 서쪽은 270도가 됩니다. 완전히 평편할 경우 GIS 시스템마다 다른 값을 주게 되는데, 여기서는 Null 값을 줍니다. (사실 Null은 값이 없다는 의미이므로, 좀더 정화하게 한다면 0~360이 아닌 다른 값을 주어야 옳습니다. 예를들어서 -1과 같은 값이 적당하겠습니다)
실제로 구현된 경사와 향에 대한 실행 결과는 아래와 같습니다. 각각 경사와 향에 대한 이미지입니다.
가만이 보면 향의 분석 결과가 불완전하기는 하지만 음영기복도(Hillshade)와 비슷해 보입니다. 여기서 Hillshade는 태양광의 위치를 정해주면 태양광의 영향으로 지형 데이터를 입체감 있게 표현해 주는 방법입니다. 아래는 이러한 내용으로 개발한 맵 엔진에 구현된 Hillshade의 결과입니다.
태양의 위치는 북동쪽(270)이고 고도는 45도로 정했습니다. 위의 Hillshade의 결과는 비록 입체적으로 보이기는 하지만 마치 석고를 발라 놓은 듯이 매우 딱딱해 보입니다. 이를 좀더 예술적(?)으로 표현하기 위해 이 글의 가장 처음 보여드렸던 지형 데이터의 원본 이미지와 위의 Hillshade를 합성하게 되는데, 좀더 멋진 음영기복도를 위한 합성 방법은 Hillshade을 약간 투명하게 하고 Luminosity 방식으로 합성해야 하나, 개발한 맵 엔진에서는 Luminosity 방식의 합성을 지원하지 않아 그냥 투명도만 주어 새롭게 음영기복도를 만들어 보았습니다. 그 결과는 아래와 같습니다.
봄 계절에 맞게 색상을 넣어 보았습니다. 좀더 색상을 다체롭게 넣는다면 더 멋진 음영기복도 만들어 질 것으로 판단되며, 앞서 언급한 Luminosity 합성을 사용하면 보다 분명한 음영기복도가 만들어 질 것 입니다. 이상으로 개발한 맵 엔진에서 확장기능으로 개발한 경사, 향 그리고 Hillshade에 대한 소개를 마칩니다.
|
김형준(Dip2K)
2009/03/25 22:54
2009/03/25 22:54
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/480 |
|
|
|
|
|
|
|
IDW는 이미 알고 있는 값으로부터 알고자 하는 값을 보간하는 방법입니다. IDW를 사용하여 주어진 점 x에 대한 보간된 값 u를 결정하는 일반화된 형태의 보간 함수는 다음과 같습니다.
N은 이미 알고 있는 값의 개수, w는 가중치의 값, u는 앞서 말한 계산되어 나온 보간된 값입니다. IDW에서 중요한것은 가중치의 값에 해당되는 w에 대한 함수가 여러개 존재하며, Spepard 방식과 Liszka 방식 그리고 이들의 변종이 존재합니다. 여기서는 Spepard 방식에 대한 w값에 대해서만 살펴 보겠습니다.
위의 식이 Spepard님이 정의한 가중치 w의 값입니다. d는 보간하고자 하는 지점(x)와 이미 알고 있는 지점(xk) 사이의 공간적 거리입니다. 바로 거리(Distance)의 역(Inverse)에 대한 가중치(Weighting)라는 의미로 IDW가 된 것입니다.
p는 0보다 큰 실수값입니다. 이 p값의 범위에 따라 전체적인 보간된 양상이 다양하게 결정됩니다. p의 범위가 0~1이면 전체적인 양상이 좁고 날카로우며 1보다 크면 넓고 부드럽게 퍼져서 보간이 됩니다. 눈에 보이는 보간된 양상을 글로써 표현하려니 한계가 있는데... 이 부분에 대해서 실제 구현을 통해 살펴보도록 하겠습니다.
끝으로 IDW처럼, 이미 알고 있는 값을 통해 다른 값을 추정(보간)하는 방법 중 Kriging 기법이 있습니다. 기회가 닿는 다면 이 Kriging 기법에 대해서도 논의해 보고 싶습니다.
|
김형준(Dip2K)
2009/03/18 15:11
2009/03/18 15:11
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/478 |
|
|
|
|
|
|
|
| 많은 스플라인의 종류 중에 하나인 큐빅 스플라인을 1차원의 보간에 적용하는 것에 대해 살펴보겠습니다. Catmull-Rom 스플라인을 구성하는 구분된 부드러운 곡선들을 나타내는 키 프레임 집합을 가지며 모든 키는 곡선 상에 위치합니다. 이 루틴을 사용하기 위해서 4개의 키 프레임 값이 필요합니다. 이 4개의 키 값을 v0, v1, v2, v3라고 하고, 여기에 보간을 위하여 v1에서 v2 사이의 지정된 0~1까지의 범위를 가지는 실수값 x가 존재합니다. 아래의 f(x)의 반환값은 x값에 의해 결정이 됩니다.
여기서 M은 다음처럼 정의됩니다.
아래의 이미지는 v1에서 v2 사이의 곡선의 한 예를 나타난 것입니다. 이 곡선은 위의 수식에서 x 값을 0에서 1.0 사이의 값을 이용해 얻을 수 있습니다.
아래의 코드는 위에서 설명한 내용을 C언어로 구현한 것입니다.
이 글의 원문은 http://www.lighthouse3d.com/opengl/maths/index.php?catmullrom 입니다.
|
김형준(Dip2K)
2009/02/16 20:37
2009/02/16 20:37
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/468 |
|
|
|
|
|
|
|
이 글은 http://www.lighthouse3d.com/opengl/maths/index.php?raytriint의 글을 통해 재구성한 글로, 변역하면서 쉽게 이해할 수 있도록 내용을 약간 수정했습니다.
매개변수방정식의 형태로 편선(시작점에서 어떤 방향으로 무한하게 진행하는 선, Ray)과 삼각형의 폴리곤이 주어질때.. 이 둘이 교차하는가를 판단하는 방법에 대해 증명은 생략하고 그 방법에 대해서 알아 보겠습니다.
삼각형을 구성하는 점은 다음처럼 정의할 수 있습니다.
삼각형의 구성 점(u,v) = (1-u-v)*p0 + u*p1 + v*p2 여기서, p0, p1, p2는 삼각형 위의 이미 알고 있는 점, u >= 0, v >= 0, u + v <= 1.0
그리고 편선에 대한 매개변수방정식을 다음처럼 정의할 수 있습니다.
편선의 구성 점(t) = p + t * d 여기서, p는 편선의 시작점으로 이미 알고 있는 점, d는 편선의 방향 벡터 이제 편선과 삼각형의 교점은 삼각형의 구성 점(u,v) = 편선의 구성 점(t) 로부터 다음과 같습니다.
p + t * d = (1-u-v) * p0 + u*p1 + v*p2 결국... 교차 여부는 세 값(t, u, v)가 위의 공식을 만족하고 u와 v가 앞서 정의한 조건을 만족하면 교차하는 경우이다. 이런 수학적인 논의는 다음으로 미루기로 하고.... 여러분이 원하는 C 코드로 대신합니다.
vector 함수는 두개의 좌표로부터 백터를 만드는 함수이고 innerProduct와 crossProduct는 내적과 외적을 구하는 함수입니다.
|
김형준(Dip2K)
2009/02/11 21:09
2009/02/11 21:09
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/467 |
|
|
|
|
|
|
|
시작점에서 어떤 방향으로 무한히 뻗어 나가는 선을 편선(Ray)이라고하자. 시작점 p와 방향벡터 d로 정의된 편선이 있을때, 이 편선이 구(Sphere)와 교차하는지 확인하는 방법에 대해 생각해보자. 교차한다면 교차점은 하나 인가, 아니면 두개인가? 아래의 그림은 여개의 상황을 보여준다.
첫번째 질문은 편선과 구가 교차하는지의 여부인데, 이를 위해서 구의 중심점에서 편선까지의 거리를 구해야만 한다. 만약 그 거리가 구의 반지름보다 크다면 교차하지 않는다고 할 수 있다.
거리를 구하기 위해, 2가지 경우를 고려해야 하는데... 구의 중심점이 편선에 투영되는지 투영되지 않는지이다. 이는 내적을 통해 알 수 있다.
구의 중심점을 c라고 하고, p에서 c까지 가는 벡터를 v라고 하자. 그렇다면 만약.......
- d ∙ v > 0 이면 투영되므로 거리를 구할 수 있다는 것이고
- d ∙ v <= 0 이면 편선 뒤에 구가 있어 투영되지 않아 거리를 구할 수 없다는 것이다.
위의 두 경에 대해서 편선과 구와의 교차에 대해 살펴보도록 하자.
구의 중심점이 편선에 투영될 경우
아래의 그림은 투영될 경우에 대해서 가능한 3가지 경우이다. 구A는 교차하지 않는 것이고, 구B는 한 점에서만 교차하고 구C는 2점에서 교차한다.
편선 위에 구의 중심점의 투영을 계산해보자. pc를 투영된 점이라고 하면, 구A에 대한 편선 위의 투영점은 pcA이고 구B에 대한 것은 pcB, 구C에 대한 것은 pcC가 된다. pc에서 구의 중심점까지의 거리가 구의 반지름보다 크다면 교차하지 않는 것이고 구A가 그렇다. pc에서 구의 중심점까지의 거리가 구의 반지름과 같다면 한점에서 만나는 것이고 구B가 그 경우이고 교차점은 점 pc이다.
구C에 대한 경우는 반지름보다 그 거리가 작은 경우이고 2개의 교차점이 존재하며 이 2개의 교차점을 구하기 위해서는 좀더 생각을 해야 하는데... 다음과 같다.
먼저 점 pc는 내적을 이용한 투영을 통해 구할 수 있다. 투영법은 이 블로그의 투영에 관한 글을 참조하기 바란다. 그리고 두개의 교차점을 i1, i2라고 하자. 다음의 과정을 통해 i1을 얻을 수 있다.
p에서 i1까지 거리를 알고 있다고 가정하면, 이 거리를 di1이라고 하고 i1은 다음 공식을 통해 구할 수 있다.
i1 = p + d * di1
위의 공식에서 p와 d는 이미 알고 있으므로, di1을 구하는 것만 남게 된다. 점i1, pc, c로 구성된 삼각형이 직각삼각형이므로, 피타고라스(Pythagorean) 공식을 적용해보면, 삼각형의 변의 길이를 a,b,c라고 할때...
- a = |c - i1| = 구의 반지름값
- b = |pc - c|
- c = |pc - i1|
위에서 오직 길이 c만이 미지수이며, 길이 c는 다음처럼 계산할 수 있다.
c^2 = a^2 - b^2 그림을 통해 di1은 다음과 같음을 알수있다.
di1 = |pc - p| - c
앞서 계산한 di1은 편선의 시작점(p)가 구의 내부에 있지 않다고 가정한 것이다. 만약 p가 구 안쪽에 있다면 di1에 대한 계산은 아래처럼 달라진다.
di1 = |pc - p| + c
구의 중심점이 편선에 투영되지 않는 경우
구의 중심점이 편선에 투영되지 않는 경우, 편선의 시작점이 구의 외부에 위치한다면 편선과 구가 교차하지 않는다는 것이다. 반면에... 편선의 시작점 p와 구의 중심점 c까지의 거리가 구의 반지름과 작거나 같다면 교차점이 존재한다. 같다면 p 자체가 교차점이다.
편선의 시작점이 구의 내부에 위치한다면, 앞의 구의 중섬점이 편선에 투영되는 경우와 같은 방법을 적용하여 교차점을 구할 수 있다. 아래 그림을 살펴면...
pc에서 i1까지의 거리 계산은 앞에서 본 것과 동일하다. 거리를 dist로 놓고.. di1은 다음처럼 계산할 수 있다.
di1 = dist - | pc - p |
|
김형준(Dip2K)
2009/02/07 11:57
2009/02/07 11:57
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/465 |
|
|
|
|
|
|
|
이 글의 원문은 http://www.lighthouse3d.com/opengl/maths/index.php?planes
원문의 내용을 그대로 번역한 것이 아닌, 제가 이해하고 이해한 내용에 대해 내용을 추가하였으며 좀 더 쉽게 풀어서 다시 작성한 글입니다.
3차원 상에서 평면은 많은 방법으로 표현할 수 있습니다. 그러나 이 모든 방법들은 모두 평면 상에 존재하는 세개의 점을 알고 있다는 가정 아래서 표현이 됩니다. 여하튼..... 가장 일반적인 평면을 기술하는 수학적인 공식은 다음과 같습니다.
평면 상에 존재하는 점을 p0, p1, p2라고 하면, 계수 A, B, C와 D는 다음과 같은 절차로 계산됩니다.
- 벡터 v와 u를 구하며, 벡터 v = p1 - p0, u = p2 - p0이다.
- 벡터 n = v x u (v와 u의 외적)
- 벡터 n을 정규화(크기가 1인 단위벡터화)
- 벡터 n=(xn, yn, zn)이라고 한다면 계수 A=xn, B=yn, C=zn 임
- 계수 D를 구하기 위해 앞에서 제시한 평면의 공식을 D에 대해 전개. 즉, -D = Ax + By + Cz
- 평면 상의 점(예를 들어 p0)에 대해 위의 공식의 x, y, z에 값을 대입하여 D를 구함(이 값은 내적을 이용해 쉽게 구할 수 있음. 즉, D = -n ∙ p0)
어떤 점에서 평면까지의 거리와 그 의미
이 블로그의 포스팅된 글에 중에 이와 관련된 글이 있지만, 평면에 대한 공식을 알아보니.. 복습 차원에서 다시 한번 정리해 보겠습니다.
앞에서 평면 방정식의 계수를 구하는 방법을 이용해 얻은 평면의 공식 Ax + By + Cz + D = 0 이 있다고 할때, 이 평면과 어떤 점 r 사이의 거리는... 만약 r이 (xr, yr, zr)이라면 이 좌표를 위의 평면의 방정식에 대입하여 D에 대해 전개하여 구한 값에 대해 절대값을 취하면 됩니다. 즉, D = |Axr + Byr + Czr|이며 이는 내적의 공식을 이용해서 다음처럼 표현할 수 있습니다.
거리값이므로 D에 대해서 절대값을 취했는데, 그렇다면 이 부호의 의미는 무엇일까요? 먼저 D 값이 0이라면 r은 평면 상에 존재하는 점입니다. r이 양수라면 평면을 기준으로 벡터 n의 방향에 있는 공간상에 r이 존재하고 음수라면 그 반대 방향에 존재합니다.
평면상에 어떤 점을 투영
점 q를 평면 Ax + By + Cz + D = 0에 투영한 점은 q에서 가장 가까운 평면상의 점입니다. q에서 평면까지의 부호있는 거리(계수 D)를 dist라고 한다면... 평면상에 가장 가까운 점 p는 다음과 같습니다.
|
김형준(Dip2K)
2009/02/01 12:13
2009/02/01 12:13
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/463 |
|
|
|
|
|
|
|
선에 대한 수학적 표현인, 선에 대한 방정식은 좌표와 벡터로 설명될 수 있습니다. 어떤 선이 있다고 해 보면, 그 선이 점p를 지나고 선의 방향은 벡터v라고 한다면 아래 그림처럼 상상해 볼 수 있습니다.
아래의 공식은 선을 구성하는 좌표를 얻는데 사용할 수 있습니다.
t는 스칼라입니다. t값에 의해 선 상의 모든 좌표를 얻을 수 있습니다. t가 0이면 좌표 p가 얻어집니다. t가 0이 아닌 다른 값이면 선 상의 다른 좌표가 얻어집니다. 백터는 2개의 좌표로부터 생성되어지므로 v는 선을 지나는 2개의 좌표를 통해 얻어집니다. p이외에 선을 지나는 다른 한 점을 p1이라고 하면 v는 p1 - p가 됩니다.
선은 양쪽 방향으로 계속 이어지며 확장된다는 것이고 광선(Ray)은 한 방향으로만 계속 이어지며 확장된다는 것으로 정의할 수 있습니다.
위의 그림에서 상단은 선이고 하단은 광선입니다. 위의 공식을 통해 다시 살펴보면, 선과 광선의 차이점은 t가 가질수 있는 값의 범위가 다르다는 점입니다. 선에서 t는 제한이 없으며, 광선에서 t는 음수가 될 수 없습니다.
선과 어떤 좌표 사이의 최단 거리
어떤 좌표와 어떤 선 사이의 가장 짧은 거리는 그 좌표에서 그 선에 수직인, 선 상의 좌표로 구성되는 선분의 길이입니다. 좌표p와 백터v로부터 정의되는 선에 대해서 살펴보겠습니다. 어떤 좌표q에서 이 선(좌표p와 벡터v로 결정)까지의 거리를 계산하는 것이 목표입니다.
위의 그림은 좌표q에서 선까지의 거리가 좌표q와 좌표q'까지의 거리임을 보여줍니다. 좌표q'는 백터u를 백터v에 대해서 투영함으로써 얻어집니다. 백터간의 투영에 대해서는 이미 알고 있다고 가정하고 만약 모르신다면 이 블로그의 글을 참조하시길 바랍니다. 여하튼, 이 투영된 벡터 puv는 다음과 같습니다.
이제 q'는 아래처럼 정해질 수 있습니다.
이제 최단 거리는 q와 q' 사이의 거리가 됩니다.
광선과 좌표 사이의 최단 거리
최단거리의 결과로 광선에 대해서 투영된 좌표들에 대해 동일한 결과 공식을 예상했으나, 다음 그림에서 보는 것처럼 항상 옳바르지는 않습니다.
앞서 어떤 좌표q와 선 사이의 거리를 위해 제시된 공식은 오직 광선 내에서 투영될 수 있을때만 의미가 있습니다. 백터u와 백터v에 대한 내적을 통해서 광선 내에서 투영되는지 검사할 수 있습니다. 즉, 백터 u와 v 사이의 코사인 각도가 음수라면 광선 내에서 투영되지 않는다는 것입니다. 코사인 각이 음수여서 광선에 투영되지 않는다면, 좌표q에서 그 광선까지의 최단 거리는 좌표q에서 광선의 시작점까지의 거리를 계산해서 쉽게 알 수 있습니다.
|
김형준(Dip2K)
2009/01/19 22:50
2009/01/19 22:50
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/459 |
|
|
|
|
|
|
|
이 글의 목적은 백터v 위로 백터u를 투영하는 것에 대한 방법을 살펴보는 것입니다.
위 그림에서 백터puv는 백터v 위에 백터u를 투영한 것입니다. 그림에서 보면 알 수 있듯이, v와 puv는 평행하므로 puv는 다음처럼 정의될 수 있습니다. 물론 여기서 백터v는 크기가 1인 단위백터입니다.
여기서 |puv|는 puv의 길이입니다. |puv|를 알아내는 것이 곧 백터puv를 알아내는 것 입니다. 백터u와 백터puv의 길이 사이의 관계는 이 두 백터가 이루는 코사인 각입니다.
내적(Dot Product)의 정의는 다음과 같습니다.
위의 정의로부터, 백터puv의 길이는 다음과 같습니다.
결국, 이 글의 가장 처음에 언급한 공식으로부터 위의 식을 대입하면 다음과 같은 puv를 얻을 수 있습니다.
|
김형준(Dip2K)
2009/01/15 21:56
2009/01/15 21:56
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/460 |
|
|
|
|
|
|
|
두 개의 벡터에 대한 내적의 연산 결과는 스칼라 값입니다. 두 벡터 사이의 코사인값을 얻는 것은 간단합니다. 아래의 식은 두 벡터 v1, v2에 대한 내적 v를 계산하기 위한 필요한 단계를 보여주고 있습니다. 내적의 연산은 일반적으로 ' ∙ ' 로 표시합니다.
벡터 v1과 v2 사이의 각도로 표시하는 방법으로 하면 다음처럼 나타낼 수 있습니다.
위의 식으로부터 우리는 두 벡터중에 하나라도 크기가 0이면 내적 역시 0이 된다는 것을 알 수 있으며 두 벡터가 수직(90도)일 경우도 내적이 0이라는 것을 알 수 있습니다. 아래는 내적에 대한 몇가지 성질입니다. 즉, 교환법칙과 분배법칙 모두 성립한다는 것입니다.
|
김형준(Dip2K)
2009/01/15 21:55
2009/01/15 21:55
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/461 |
|
|
|
|
|
|
|
두개의 벡터에 대한 외적은 또 하나의 새로운 벡터를 정의합니다. 두개의 벡터가 이루는 하나의 평면에 대해 수직인 벡터가 바로 외적에 의해 만들어지는 새로운 벡터입니다. 외적은 두 벡터가 이루는 각을 구하는 것이라든지, 광원에 대한 계산, 즉 빛의 방향을 구하는 계산 등에 응용됩니다.
아래의 공식은 두개의 벡터 v1, v2에 대한 외적 v를 구하기 위해 필요한 과정을 보여주고 있습니다. 외적 연산의 기호는 ' X '를 일반적으로 많이 사용합니다.
벡터 v1과 v2의 시작점을 원점이라고 할때, 벡터v1과 v2가 이루는 평면이 X축과 Z축이 구성하는 평면인 XZ라고 하면 외적에 의한 벡터는 v1에서 v2가 반시계방향이면 Y축 방향으로 위를 향하고 시계방향이면 Y축 방향으로 아래를 향합니다. 두 벡터의 외적에 대한 일반적인 성질은 아래와 같습니다. 내적과는 다르게 외적은 교환법칙이 성립하지 않습니다. 아래의 식에서 k는 스칼라값입니다.
벡터v1과 v2가 이루는 사인각으로도 외적을 표시할 수 있으며, 다음과 같습니다.
위의 식에서 a가 두벡터 사이의 각도 입니다. 위 공식에서 보듯, 외적도 내적과 마찬가지로 두 벡터가 이루는 각을 구하는데 사용할 수 있습니다.
|
김형준(Dip2K)
2009/01/08 10:26
2009/01/08 10:26
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/462 |
|
|
|
|
|
|
|
| 폴리곤이 오목한지 볼록한지에 대한 각각의 경에 대해서, 좌표가 시계방향으로 되어 있는지, 반시계 방향으로 되어 있는지를 검사하기 위한 방법입니다. GIS에서 폴리곤 도형에 대해 시계방향인지 반시계방향인지에 따라 폴리곤에 대한 구멍(Hole)인지의 여부를 결정짓는 경우가 있습니다. 이외에 폴리곤의 앞면인지 뒷면인지의 여부도 시계방향인지의 여부에 따라 결정됩니다.
먼저 폴리곤의 구성하는 좌표의 개수가 N개라고 하고, 구성 좌표를 아래처럼 표기합니다.
볼록한 폴리곤에 대해서 좌표의 방향에 대한 간단한 검사는 인접한 좌표들이 이루는 선분(벡터)에 대한 외적(Cross Product)을 통해 가능합니다. 만약에 외적이 양수이면 수직벡터가 폴리곤이 이루는 평면(z축이 평면의 위쪽으로 향한다고 가정) 윗 방향이고, 음수이면 평면의 안쪽 즉 평면에 대해 아래 방향으로 향합니다.
오목한 폴리곤의 경우는 폴리곤의 면적을 계산함으로써 알 수가 있습니다. 면적을 계산하는 공식은 다음과 같습니다. (왜 이렇게 되는지는 블로그의 다른 글을 통해 곧 소개 하겠습니다)
위의 값이 양수이면 폴리곤의 구성 좌표의 구성 순서가 시계 반대 방향이고, 음수이면 시계 방향임을 나타냅니다.
이제 그렇다면, 뒤집어서.... 폴리곤이 오목한지 볼록한지는 어떻게 알 수 있을까요? 그것은 볼록한 폴리곤을 이루는 인접한 선분 벡터들은 모두 같은 부호이지만, 오목한 폴리곤의 경우는 부호가 섞여 있다는 것으로 알 수 있습니다.
|
김형준(Dip2K)
2009/01/06 23:58
2009/01/06 23:58
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/457 |
|
|
|
|
|
|
|
평면의 방정식은 아래처럼 기술할 수 있으며, (A, B, C)는 평면에 대한 법선(수직) 백터이고.. D는 이 법선 백터의 길이(크기)입니다. (x,y,z)는 평면상의 임이의 점입니다.
평면은 최소한 점 3개가 정해지면 평면의 방정식이 명확히 정의됩니다. 즉, 평면 상의 (x1,y1,z1)과 (x2, y2, z2) 그리고 (x3, y3, z3)가 정해지면 위의 공식에서 A, B, C, D의 값이 정해진다는 의미입니다. 각 A,B,C,D는 정해진 점들에 대해서 다음과 같은 행렬식으로 정의되며...
위의 행렬식은 다음과 같이 다시 한번 전개가 됩니다.
결국 이렇게 구한 A,B,C,D로부터 평면의 방정식이 결정되게 됩니다.
|
김형준(Dip2K)
2009/01/05 11:43
2009/01/05 11:43
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/456 |
|
|
|
|
|
|
|
하나의 평면에 대해서 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과 동일합니다.
|
김형준(Dip2K)
2009/01/05 10:52
2009/01/05 10:52
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/455 |
Tracked from Phentermine price.
2009/11/22 18:57 x
제목 : Phentermine prozac.
No prescription phentermine. Phentermine without a prescription. Phentermine. Effects phentermine. Phentermine line. Phentermine cod....more
|
Tracked from Adderall.
2009/11/28 03:57 x
제목 : Side effects of adderall.
Adderall coupon. Top foreign pharmacy to buy adderall. Adderall without prescription. Ordering adderall. Adderall alcohol. Adderall and migraines. Adderall. Adderall addiction....more
|
|
|
|
|
|
|
|
원문은 http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ 입니다.
지금 진행하고 있는 프로젝트에서 필요한 알고리즘인데, 어디 이미 구현된 소스 코드 없나... 찾다가 발견한것입니다. 찾고보니, 무척 오래전에 봤던 글이네요. 그런데 그때는 소스 코드를 제공하지 않았는데... 여하튼, 다시 복습하는 겸해서 번역해 올립니다. 예전과 다르게 그림도 깔끔해서 그 그림을 그대로 올리겠습니다. 물론 변역이기는 하지만, 나름대로 내용을 보충해서 올렸습니다. 내용 시작합니다~
P1(x1, y1)과 P2(x2, y2)를 지나는 선분의 공식은 아래와 같다.
P = P1 + u(P2 - P1)
점 P3(x3, y3)는 P1과 P2를 지나는 선분에 인접한 점이다. P3를 선분까지 수직으로 연장한 길이가 바로 우리가 구하고자 하는 값, 즉 최소 거리이다. 수직으로 연장해서 만나는 점을 P라고 하자. 즉, P는 선분 상의 점이 되겠다. 그렇다면, 벡터P3->P와 벡터 P2->P1를 정의할 수 있을 것이고, 이 두 벡터의 내적(Dot Product)는 0이다.
(P3 - P) dot (P2 - P1) = 0
위의 식의 P에 처음에 언급한 선분의 식(P에 대한)을 대입해보면...
[P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0
위의 식을 u에 대해서 풀어보면,
이 u 값을 다시 처음의 선분의 방정식(P1과 P2를 지나는)에 대입해 교점P에 대한 x, y에 대해 풀어보면...
x = x1 + u(x2 - x1)
y = y2 + u(y2 - y1)
그렇다면... 이렇게 구한 P와 P3의 거리가 바로 우리가 구하고자 했던 최소 거리값이 된다.
|
김형준(Dip2K)
2008/03/22 20:16
2008/03/22 20:16
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/384 |
|
|
|
|
|
|
|
오늘 최홍만이 K1에서 K.O. 를 당했다. 상대가 자주 큰 스윙훅을 휘두르는데, 저거 한대 맞겠다 싶던 찰라에 한대 맞고 링 바닦에 누워버렸다... 너무 아쉽다. 하지만 오히려 최홍만에게는 약이 될것같다.
각설하고... 어제와 오늘, 조용히 정렬 알고리즘에 대해 살펴보았다. 전에 내가 알고 있는 정렬 알고리즘은 Bubble Sort와 Quick Sort 뿐이였는데, 이 외에도 다양한 정렬 알고리즘이 있다는 것을 알았다. 각각의 알고리즘에 대한 원리를 이해하고 실제로 직접 구현해본 코드를 남겨둔다.
먼저 예로 사용되는 data의 정의는 다음과 같다.
const size_t cntData = 20;
int data[cntData]; 첫번째, Selection Sort
void selectionSort(int data[], size_t cntData) {
for(size_t beginIdx=0; beginIdx<cntData-1; beginIdx++) {
int minData = data[beginIdx];
size_t minDataIdx = beginIdx;
for(size_t i=beginIdx+1; i<cntData; i++) {
if(minData>data[i]) {
minData = data[i];
minDataIdx = i;
}
}
data[minDataIdx] = data[beginIdx];
data[beginIdx] = minData;
}
} 두번째, Insertion Sort
void insertionSort(int data[], size_t cntData) {
int t;
size_t j;
for(size_t i=1; i<cntData; i++) {
t = data[i];
j = i;
while(data[j-1]>t && j>0) {
data[j] = data[j-1];
j--;
}
data[j] = t;
}
} 세번째, 최악의 Bubble Sort
void bubbleSort(int data[], size_t cntData) {
for(size_t i=cntData-1; i>0; i--) {
for(size_t j=0; j<i; j++) {
if(data[j]>data[j+1]) {
int tmpData = data[j];
data[j] = data[j+1];
data[j+1] = tmpData;
}
}
}
} 네번째, Insertion Sort를 응용한 Shell Sort
void ShellSort(int data[], size_t cntData) {
size_t h;
for(h=1; h<cntData; h=3*h+1);
for(h/=3; h>0; h/=3) {
for(size_t i=0; i<h; i++) {
for(size_t j=i+h; j<cntData; j+=h) {
int v = data[j];
size_t k = j;
while(data[k-h]>v && k>(h-1)) {
data[k] = data[k-h];
k -= h;
}
data[k] = v;
}
}
}
} 다섯번째, 응용에 제한적인 Distribution Counting Sort
void distributionCounting(int data[], size_t cntData,
int startValue, int endValue) {
const size_t cntType = endValue-startValue+1;
int *count = new int[cntType];
for(size_t i=0; i<cntType; i++) {
count[i] = 0;
}
for(size_t i=0; i<cntData; i++) {
count[data[i]]++;
}
for(size_t i=1; i<cntType; i++) {
count[i] += count[i-1];
}
int *tmp = new int[cntData];
for(int i=cntData-1; i>=0; i--) {
tmp[--count[data[i]]] = data[i];
}
for(size_t i=0; i<cntData; i++) {
data[i] = tmp[i];
}
delete [] tmp;
delete [] count;
} 여섯번째, Quick Sort
void quickSort(int data[], size_t cntData) {
int pivot, tmp;
int i, j;
if(cntData > 1) {
pivot = data[cntData-1];
i = -1;
j = cntData - 1;
while(true) {
while(data[++i] < pivot);
while(data[--j] > pivot);
if(i >= j) break;
tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
data[cntData-1] = data[i];
data[i] = pivot;
quickSort(data, i);
quickSort(data+i+1, cntData-i-1);
}
} 일곱번째, 기수정렬(Radix Sort)
기수정렬 중, 기수교환정렬(Radix Exchange Sort)
unsigned long bit(unsigned data, int b) {
return data & (1 << b);
}
void radixExchangeSort(int data[], size_t cntData, int b) {
int t, i, j;
if(cntData>1 && b>=0) {
i = 0;
j = cntData - 1;
while(true) {
while(bit(data[i], b)==0 && i<j) i++;
while(bit(data[j], b)!=0 && i<j) j--;
if(i>=j) break;
t = data[i];
data[i] = data[j];
data[j] = t;
}
if(bit(data[cntData-1], b) == 0) j++;
radixExchangeSort(data, j, b-1);
radixExchangeSort(data+j, cntData-j, b-1);
}
} 기수교환정렬 중, 직접기수정렬(Straight Radix Sort)
unsigned bits(unsigned data, int startBitIndex, int count) {
return (data >> count) & ~(~0 << startBitIndex);
}
void straightRadixSort(int data[], size_t cntData) {
int i, j;
int *tempData, *count;
const size_t sizeBitData = sizeof(data[0]) * 8;
const size_t bitCount = 4;
const size_t cntCountArray = (1<<bitCount);
tempData = (int *)malloc(sizeof(int)*cntData);
count = (int *)malloc(sizeof(int)*cntCountArray);
for(i=0; i<sizeBitData/bitCount; i++) {
for(j=0; j<cntCountArray; j++)
count[j] = 0;
for(j=0; j<cntData; j++)
count[bits(data[j], i*bitCount, bitCount)]++;
for(j=1; j<cntCountArray; j++)
count[j] += count[j-1];
for(j=cntData-1; j>=0; j--)
tempData[--count[bits(data[j], i*bitCount, bitCount)]] =
data[j];
for(j=0; j<cntData; j++)
data[j] = tempData[j];
}
free(count);
free(tempData);
} 끝으로 위의 코드에 대한 최적화는 전혀 되어 있지 않다. 하나의 예로 정렬 알고리즘 중 가장 많이 사용하는 Quick Sort의 경우에 재귀호출을 사용하는데, 많은 개수의 데이터를 정렬하는 실제 상황에서는 비재귀 형태로 수정되어야 한다. 또한 학습한 책에는 나와 있으나, 이해만 하고 구현해보지 못한 정렬 알고리즘으로 Heap Sort와 Merge Sort가 있다.
|
김형준(Dip2K)
2007/03/04 20:05
2007/03/04 20:05
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/206 |
|
|
|
|
|
|
|
정규분포(Normal Distribution)이라고도 하는 이 정규분산을 이루는 난수 발생의 필요는 어떤 폴리곤 안에 무작위로 점을 찍어야할 경우에서이다.
처음의 접근은 단순히 폴리곤 안의 점을 무작위로 발생시켜 찍었으나, 폴리곤 안의 점들이 너무 고르게 분포되어져 있다는 문제점이 있었다. 폴리곤의 중심으로 점들이 몰리도록하는 방법이 무엇을까 생각해보니, 가우스분산을 이루도록 점들이 폴리곤안에 난수로 발생시키도록 하였다.
가우스분산을 이루는 난수발생.... 가우스분산이라는 정의를 곰곰이 들여다보면, 어떤 구간에서 그 구간의 중심점에 더 많은 빈도(가중치)가 몰린다는 것이다. 그렇다면 몇번의 난수를 발생시켜 그 평균을 구한다면, 그 값이 가우스분산을 이루는 난수가 아니겠는가?
아래는 이러한 생각에 의한 실제 구현된 코드이다.
double gaussDistributeRand(double begin, double end, size_t detail=5) {
double r = 0;
for(size_t i=0; i<detail; i++)
r += (double)rand()/(double)RAND_MAX;
r /= (double)detail;
return r*(end-begin)+begin;
} 인자 detail은 난수를 몇번 발생시켜 평균을 구할 것인가에 대한 것으로 이 값이 커질수록 난수발생값이 중심(평균)으로 집중하는 강도를 나타낸다.
실제로 위의 코드를 적용해서 detail을 1(가우스분산이 아닌 그냥 난수발생), 2, 4, 8, 20, 100으로 주었을때의 실행결과를 보면 아래와 같다.
이미 언급한것과 같이 결과에서도 알수있듯 detail값이 커질 수록 중심으로 난수발생값이 집중된다는 것을 알 수 있다.
|
김형준(Dip2K)
2007/01/24 12:27
2007/01/24 12:27
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/187 |
|
|
|
|
|
|
|
GIS 엔진은 내부적으로 엄청난 수의 도형을 검색하여 화면에 그리는데, 추구하는 목표는 얼마나 빠르게 검색하여 얼마나 빨리 그리느냐는 것. 이것은 로컬에 대한 경우이고 서버와 클라이언트의 개념으로 확장하면 신속한 검색과 빠른 그리기는 기본이고 추가적으로 서버가 얼마나 빠르게 클라이언트로 도형의 좌표 데이터를 전송하는가까지 고민해 봐야 한다. 그리기에 한정해서 볼때, 윈도우즈 GDI API는 윈도우즈 운영체제 초기버전부터 지금까지 지속적으로 개선되고 발전해 왔으며 GDI+로 대체되는 듯 하지만, 여전히 속도를 요구하는 부분에서는 GDI+ 보다는 GDI를 사용한다. 이러한 GDI API를 이용하여 폴리라인을 그릴때, 화면을 벗어나는 폴리라인을 무시하고 화면에 보이는 폴리라인만 따로 계산하여 그려야할 필요가 없을 정도로 GDI API는 실패하지 않고 성공적으로 또한 빠르게 작동한다. 하나의 예로 아래의 그림과 같은 상황에서도 무리없이 폴리라인을 그려낼 수 있다.
즉, 위의 폴리라인의 구성좌표(좌표값이 몇만단위)를 그대로 GDI API를 사용하여 그려도 얼마간의, 그러나 충분히 무시할 수 있는 성능의 희생만으로 화면상에 빠르게 그릴 수 있다.
그런데 왜 필자가 폴리라인을 사각영역에 대해 클리핑하는 방법을 필요로 했는가? 이유는 오렌지맵을 네트워크 버전으로 확장하면서 폴리라인이나 폴리곤을 임이의 사각영역에 대해 클리핑 해야만 한다는 절대적인 필요성을 느꼈기 때문이다. 즉, 클라이언트에서 서버에게 자신의 화면영역을 전달하면 서버는 그 영역에 해당하는 도형을 신속하게 검색하여 클라이언트에게 검색된 도형의 좌표들을 전송해준다. 이때, 검색된 도형의 좌표를 모두 전송하지 않고, 화면상(사각영역)에 들어가는 폴리라인의 좌표만을 전송해준다면 네트워크 상의 속도는 훨씬 더 향상될 것이다. 실제로 GIS에서는 등고선과 도로망도 등, 아주 긴 폴리라인을 아주 많이, 굉장이 많이 사용하게 되는데 꽤 이름이 알려진 상용 GIS 서버들 조차 이러한 경우에 매우 비효율적인 전송 방법, 즉 검색된 도형의 모든 좌표를 전송한다는 것이다. 대부분 GIS 서버들은 이러한 문제를 해결하기 위해서 폴리라인을 세그먼트화(폴리곤을 일정한 간격으로 계속 자르는 방법)하여 해결한다. 그러나 이러한 데이터를 재처리하는 방법은 불필요한 좌표 중복이 심하게 발생하는데, 이는 세그먼트화된 폴리라인들은 서로 시작 좌표와 끝 좌표를 중복하여 유지해야 하기 때문이다. 이러한 GIS 데이터 차원에서의 해결이 아닌 프로그램에서의 처리방법이 바로 폴리라인의 클리핑이다. 참고로 아래의 알고리즘은 필자가 개발하고 있는 오렌지박스 Map 서버에서 실제로 사용하였으며 등고선과 같은 데이터의 경우, 서버가 클라이언트로 전송해야할 데이터의 크기를 획기적으로 줄일 수 있었다.
대상이 되는 폴리라인과 기준이 되는 사각영역을 아래의 그림을 예로 들어 설명한다.
위의 그림을 보면 하나의 폴리라인이 사각영역에 의해 클리핑되어 4개의 폴리라인이 되는 것을 알 수 있다. 클리핑 되기전의 폴리라인은 총 17개의 시작점과 끝점으로 구성된 선으로 이루어져 있고, 사각영역은 4개의 선으로 이루어져 있다. 선과 선의 교차 알고리즘(본 블로그에 있음)을 이용하여 사각영역을 구성하는 선과 폴리라인과의 교차점(아래 그림의 빨간색점)을 구할 수 있다.
위의 그림을 보면 클리핑된 폴리라인의 시작점과 끝점의 사격영역과 폴리라인의 교차점이라는 사실을 알 수 있다. 하지만 예외가 있는데 아래의 그림이 바로 그 예외이다.
즉, 폴리라인의 시작점이나 끝점이 사각영역의 내부에 위치할 경우 클리핑된 폴리라인의 시작점과 끝점이 교차점이 아니라는 예외가 발생한다. 하지만 이런 예외는 단순히 클리핑되기 이전의 폴리라인의 시작점과 끝점이 사각영역 내부에 있을 경우 교차점으로 판정한다고 결정하면 해결된다.
자, 이제 위에서 언급한 내용을 토대로 실제로 클립핑된 폴리라인들의 좌표를 구성하는 과정을 단계별로 그림으로 살펴보자.
첫단계인 위의 그림에서 처럼, 먼저 폴리라인을 구성하는 첫 라인에 대해서 사각영역과의 교차점을 구한다. 여기서 첫 라인의 시작점이 경계상자 안에 위치하므로 내부버퍼에 저장하고 교차점도 저장한다. 그러나 끝점은 경계상자의 밖에 위치하므로 버린다. 내부 버퍼에 저장된 좌표와 상태를 위의 그림과 함께 나타내었다. 내부 버퍼의 상태에서 Yes와 No는 각각 해당 좌표가 교차점인가 아닌가를 나타내는 것이다.
두번째 단계에 대한 그림은 아래와 같다.
선의 시작점인 V2는 경계상자의 밖에 위치하므로 무시하고 끝점인 V3는 경계상자의 안에 위치하므로 내부버퍼에 저장한다. 물론 V3를 저장하기에 앞서 교차점인 ip2를 저장해야한다.
세번째 단계에 대한 그림은 아래와 같다.
세번째 단계는 선의 시작점과 끝점 모두 경계상자 내부에 위치하는 경우이므로 두점 모두 유효하다. 그러나 시작점은 이미 버퍼에 저장된 최근 좌표와 중복되므로 무시할 수 있다. 이때 저장되 최근 좌표의 종류가 교차점이라면 무시해서는 않된다.
네번째 단계는 첫번째 단계와 동일하므로 설명을 생략하고 다섯번째 단계를 살펴보면....
선의 시작점과 끝점이 모두 경계상자 밖에 위치하므로 교차점은 없거나 두개가 생기게 된다. 교차점이 없다면 내부버퍼에 저장할 것이 없지만 교차점이 두개인 경우 그 두개의 교차점을 내부 버퍼에 저장한다. 이때 중요한 것은 시작점과 가까운 교차점을 먼저 저장해야한다.
이제 마지막 선에 대해 계산을 해보면...
마지막 단계는 이전 단계와 같은 상황이므로 따로 설명할 필요는 없는 듯하다.
이제 폴리라인의 모든 선분들에 대해서 계산을 끝낸 최종결과가 내부버퍼에 저장되어져 있으므로 이 버퍼를 이용해 클리핑된 폴리라인을 알 수 있다. 서두에서 언급했던 것처럼 내부 버퍼의 시작과 끝 좌표요소을 교차점으로 간주하기로 했다는 것을 잊지 말기 바란다. 즉 내부 버퍼는 최종적으로 아래와 같은 상태가 될것이다.
위의 최종 버퍼를 통해 폴리라인을 그리거나, 좌표를 구할 수 있다. 처음 Yes의 좌표는 폴리라인이 시작점이 되고 그 다음의 Yes를 만날때까지 동일한 폴리라인의 구성점이 되다가 Yes를 만나면 동일한 폴리라인의 끝점이 된다.
이상으로 폴리라인의 사격영역에 대한 클리핑 알고리즘에 대한 설명을 끝마친다.
이 알고리즘은 필자가 나름대로 고민하여 구상한 알고리즘으로 기존의 더 나은 알고리즘도 있을 것이다. 하지만 필자가 스스로 고민하여 만들어낸 알고리즘을 실제 프로그램상에 적용하여 만족할 만한 결과를 얻어낸 알고리즘이라는 점을 강조하고 싶다.
|
김형준(Dip2K)
2005/06/29 00:19
2005/06/29 00:19
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/21 |
Tracked from viagra
2006/11/22 17:03 x
제목 : viagra
gia fierawej...more
|
Tracked from prozac
2006/11/29 18:04 x
제목 : prozac
iawas duij...more
|
Tracked from paxil
2006/11/30 02:15 x
제목 : paxil
ki eev...more
|
Tracked from celexa
2006/12/01 19:03 x
제목 : celexa
aukunozp teuvaqud...more
|
Tracked from prozac
2006/12/02 00:18 x
제목 : prozac
unoim osuub...more
|
Tracked from ciagra
2006/12/04 14:23 x
제목 : ciagra
uwug eliyoh...more
|
Tracked from cualis
2006/12/04 16:31 x
제목 : cualis
ojoto htoi...more
|
Tracked from dialis
2006/12/04 19:35 x
제목 : dialis
tao ebocogo...more
|
Tracked from biagra
2006/12/04 21:53 x
제목 : biagra
rzoejou pvea...more
|
Tracked from xialis
2006/12/05 01:46 x
제목 : xialis
utuluqu keuki...more
|
Tracked from vuagra
2006/12/05 02:58 x
제목 : vuagra
bae eyicu...more
|
Tracked from cialis
2006/12/05 16:04 x
제목 : cialis
iut kuut...more
|
Tracked from fialis
2006/12/05 21:37 x
제목 : fialis
osowiteh ejecoma...more
|
Tracked from fiagra
2006/12/05 22:00 x
제목 : fiagra
lkeixoe qiohito...more
|
Tracked from giagra
2006/12/05 23:16 x
제목 : giagra
xwiebixe aibidonl...more
|
Tracked from paxil
2006/12/08 10:23 x
제목 : paxil
yaeju ioworij...more
|
Tracked from cialis
2006/12/09 01:31 x
제목 : cialis
meep oecg...more
|
Tracked from cialis
2006/12/18 08:33 x
제목 : cialis
tuemebe la...more
|
| | | |