최단 경로 탐색 – A* 알고리즘

최단 경로 탐색 알고리즘 중 A*(A Star, 에이 스타) 알고리즘에 대해 실제 예시를 통해 풀어가면서 설명하겠습니다. A* 알고리즘은 시작 노드만을 지정해 다른 모든 노드에 대한 최단 경로를 파악하는 다익스트라 알고리즘과 다르게 시작 노드와 목적지 노드를 분명하게 지정해 이 두 노드 간의 최단 경로를 파악할 수 있습니다.

A* 알고리즘은 휴리스틱 추정값을 통해 알고리즘을 개선할 수 있는데요. 이러한 휴리스틱 추정값을 어떤 방식으로 제공하느냐에 따라 얼마나 빨리 최단 경로를 파악할 수 있느냐가 결정됩니다.

A*에 대한 서론은 최대한 배제하고 하나의 명확한 예를 통해 풀어나가며 설명하도록 하겠습니다. 다음과 같은 예를 통해 먼저 살펴보겠습니다.

위의 예는 시작점인 0번 노드에서 목적지인 6번 노드로 가는 최단 경로를 A* 알고리즘으로 분석하고자 하는 것인데요. 각 노드 사이에 연결된 링크에 붙은 숫자는 노드 사이를 이동하는데 소요되는 비용(경비, Cost)입니다. 위의 경우 거리값입니다. 즉, 노드 사이의 거리가 길수록 비용이 늘어나므로 비용값으로써 합리적입니다.

A* 알고리즘을 통한 위의 문제 해결을 위해 가장 먼저 수행하는 첫 과정은 다음과 같습니다.

위의 그림에서 보면 저장소로 O와 C가 있는데요. O는 열린 목록(Open List), C는 닫힌 목록(Close List)인데요. 열린 목록인 O 저장소에는 최단 경로를 분석하기 위한 상태값들이 계속 갱신되며, C 저장소는 처리가 완료된 노드를 담아 두기 위한 목적으로 사용됩니다.  이러한 O와 C의 저장소를 기반으로 0번 노드에서 6번 노드까지의 최단 경로를 산출해 보도록 하겠습니다.

먼저 출발 노드인 0을 닫힌 목록인 C 목록에 집어 넣습니다. 그리고 이 0번 노드와 연결된 노드는 1번과 3번 노드를 열린 목록인 O 저장소에 추가합니다. 추가할 때 F, G, H, Parent Node값도 함게 추가해야 하는데요. 먼저 F = G + H입니다. G는 시작 노드에서 해당 노드까지의 실제 소요 경비값이고, H는 휴리스틱 추정값으로 해당 노드에서 최종 목적지까지 도달하는데 소요될 것이라고 추정되는 값입니다. Parent Node는 해당 노드에 도달하기 직전에 거치는 노드 번호입니다. 먼저 1번 노드에 대한 F, G, H, Parent Node를 살펴 보겠습니다. 출발점인 0번 노드로부터 시작했으므로,  1번 노드의 Parent Node는 0번 노드입니다. 그리고 G 값은 0번 노드에서 1번 노드까지의 거리 비용값인 5.6입니다. H 값을 추정하기 위한 기준이 필요한데요. 이 추정값에 대한 기준을  1번 노드에서 목적지인 6번 노드까지의 직선 거리로 하기로 정하고 측정을 하니(줄자로 재든, 좌표가 있다면 피타고라스 정리를 통해 두 좌표 사이의 거리를 계산하든 하여 얻을 수 있음)  12로 산출되므로 H는 12가 됩니다. F = G + H이므로 5.6 + 12인 17.6이 됩니다. 3번에 대한 F, G, H, Parent Node 역시 이와 동일하게 결정할 수 있습니다. 여기서 다음 단계로 진행합니다.


O 리스트 중 F 값이 가장 작은 노드는 3번인데요. 이 노드 3번을 C 리스트에 추가하고 3번 노드와 연결된 0, 2, 5 중 닫힌 목록에 존재하지 않는 2, 5번 노드에 대해 열린 목록에 추가합니다. 2, 5에 대한 F, G, H, Parent Node를 계산해 기록합니다. 먼저 2번 노드에 대해 계산해 보면.. 2번 노드에 대한 G 값은 바로 직전 노드에 소요되는 비용(6.8)에 3번 노드에서 2번 노드까지 도달하기 위한 비용인 5.6을 합한 값인 12.4가 됩니다. 그리고 H 값은 2번 노드에서 목적지은 6번까지에 대한 거리값인 7이 됩니다. 5번 노드에 대한 것도 이와 동일하게 계산합니다. 다음으로 진행합니다.

열린 목록(O 저장소) 중 F 값이 가장 작은(최소인) 1번 노드를 닫힌 목록에 추가합니다. 그리고 이 1번 노드와 연결된 2, 4번 노드 중 닫힌 목록(C 저장소)에 존재하지 않는 것에 대해 다시 F, G, H, Parent Node를 계산합니다. 이 상태에서 4번 노드는 열린 목록에 없었던 것이기에 그냥 F, G, H, Parent Node를 이미 앞서 설명했던 방식으로 계산해 추가하면 그만이지만 2번 노드는 전 단계에서 이미 추가되어 있었는데요. 이렇게 전 단계에서 추가된 G 값이 새롭게 계산된 G 값보다 크다면 새롭게 계산된 F, G, H, Parent Node 값으로 변경해 줘야 하며 위의 그림이 이러한 변경을 나타내고 있습니다. 다음 단계로 진행합니다.

열린 목록 중 F가 최소인 노드는 2번 노드이고, 이 2번 노드를 닫힌 목록에 추가합니다. 그리고 2번 노드와 연결된 1, 3, 5, 6번 노드 중 닫힌 목록에 존재하지 않는 5, 6번 노드에 대한 F, G, H Parent Node 값을 계산합니다. 5번 노드의 경우 새로운 G 값이 기존 값보다 크므로 변경하지 않고 6번 노드에 대한 값들만을 계산해 추가합니다. 다음 단계로 진행합니다.

열린 목록 중 F가 최소인 노드는 6번 노드인데요. 이 6번 노드를 닫힌 목록에 추가합니다. 그런데 이 6번 노드는 최종 목적지 노드이므로 A* 알고리즘은 종료됩니다.

여기까지 만들어진 닫힌 목록(C 저장소)를 토대로 0번 노드에서 6번 노드까지의 최단 경로를 파악할 수 있습니다. 6번 노드의 Parent Node는 2번 이고, 2번 노드의 Parent Node는 1번이며, 1번 노드의 Parent Node는 0번이므로 최단 경로는 6번 노드←2번 노드←1번 노드←0번 노드가 됩니다.

[FingerEyes-Xr] 이미지를 레이어로 추가하기

간단히 하나의 이미지를 지도를 구성하는 레이어로 추가하기 위한 코드에 대한 설명입니다. 예를 들어 아래처럼 TMS 등과 같은 방식으로 추가된 배경지도 위에 하나의 이미지를 중첩하고자 할때 사용할 수 있는 기능입니다.

코드의 예는 아래와 같습니다. url을 통해 중첩하고자 하는 이미지의 웹 url을 지정하고, 이미지에 대한 MBR을 minX, minY, maxX, maxY로 지정해 레이어를 생성해 추가해 주면 됩니다.

var lyr = new Xr.layers.ImageLayer(
    "imageLyr",
    {
        url: "http://www.gisdeveloper.co.kr:8080/download/map.jpg",
        minX: 150613,
        minY: 246114,
        maxX: 151129,
        maxY: 246633,
    }
);

map.layers().add(lyr);
map.update();

결과는 아래와 같습니다. 지정된 위치에 지도가 표시됩니다.

이 기능은 드론등과 같은 장치를 이용해 특정 지역에 대한 지도를 변경할때 간단히 사용할 수 있는 기능입니다.

GeoService-Xr에서 동적으로 GeoData 추가 및 삭제하기

GeoService-Xr은 공간 데이터를 GeoData라는 단위로 처리합니다. 정확하게 일치하지는 않으나 GeoData는 GIS의 Layer와 매우 유사합니다. GeoData를 새롭게 추가하거나 삭제하기 위해서는 일단 GeoService-Xr의 실행을 중지시키고 geodata.xml 파일을 통해 GeoData를 수정한 후 다시 GeoService-Xr을 재기동시킵니다. 그러나 간혹 geodata.xml 파일의 수정이 아닌 GeoService-Xr의 실행 중에 GeoData를 추가 도는 삭제가 가능합니다.

아래는 추가되어진 GeoData를 삭제하는 RestAPI 명령의 한가지 예 입니다.

http://localhost/Xr?rmGD|muan_parc_a

위의 rmGD가 ‘remove GeoData’ 명령이고 muan_parc_a가 제거하고자 하는 GeoData 식별자입니다.

아래는 새로운 GeoData를 추가하는 RestAPI 명령의 한가지 예 입니다.

http://localhost/Xr?addGD|muan_parc_a|muan_db://public."parc_a"|5186

addGD가 ‘add GeoData’ 명령이고, muan_parc_a가 GeoData의 식별자이며 muan_db://public.”parc_a”가 DBMS의 식별자(muan_db)와 테이블명(public.”parc_a”)로 지정되는 추가하고자 하는 공간 데이터 Table입니다.

이처럼 동적으로 GeoData를 추가하고 삭제하는 기능을 통해 웹 기반에서, GIS 시스템에서 유연하게 공간데이터를 핸들링할 수 있는 기반을 제공하게 됩니다.

NexGen으로 출력한 PDF 결과물

공개소프트웨어인 웹 기반의 GIS 시스템인 NexGen에서 출력한 PDF 파일입니다.

넥스젠은 웹 기반의 여타 다른 웹 GIS 시스템과 다르게 수치지도에 대한 출력은 Vector 기반으로 출력함으로써 아무리 확대를 해도 도형 데이터가 깔끔하게 표시됩니다. 이러한 장점을 십분 활용하여 플로터 등과 같은 지도 출력 장비를 활용하여 고품질의 지도를 출력할 수 있습니다.

아래의 파일은 넥스젠에서 출력한 PDF 파일 원본입니다.

NexGen 지리정보 공개소프트웨어 – 경사도, 단면도 측정 기능

넥스젠(NexGen) 지리정보 시스템은 GIS의 가장 기반이 되는 기능을 기본적으로 갖추고 있는 공개소프트웨어입니다. 넥스젠이 활용하는 공간 데이터는 이미 국가차원에서 공개하고 있는 DB로써 누구나 쉽게 획득할 수 있는 영상과 지형도, 지적도, 표고 데이터인 DEM을 활용하고 있습니다.

넥스젠은 (주)지오서비스에서 개발하고 공개한 웹 GIS 엔진인 FingerEyes-Xr for HTML5을 활용하여 (주)내가시스템과 함께 개발하였습니다. 참고로 (주)내가시스템은 GIS를 활용한 하수설비관리시스템과 하천관리시스템 분야에서 독보적인 기술력은 갖춘 회사입니다.

넥스젠이 제공하는 GIS의 기본기능은 지적주소 기반의 주소검색, 도로명주소 기반의 주소검색, 지오코딩, 레이어 관리, 그래픽 요소 매쉬업, 거리측정, 면적측정, 레이어 관리, 각 레이어에 대한 SHP 파일 내보내기, 경사도와 단면도 측정 기능 등입니다. 이 글은 넥스젠의 기본 기능 중 경사도와 단면도를 측정하는 기능을 소개합니다.

먼저 아래의 실행화면은 지형의 단면도를 측정한 화면입니다.

시스템 화면에 대한 아이콘은 실제 적용 사이트의 특색에 맞게 디자인 하도록 유도하기 위해 확정되지 않았습니다. 지형의 단면도를 측정하기 위해서는 표고 데이터인 DEM 이 필요합니다. 빠른 기능 실행을 위해 서비스에 최적화된 포맷으로 재가공되어 수십, 수백 km 거리의 지형 단면도에 대한 측정에도 빠르게 그 결과를 사용자에게 제공합니다.

다음은 평균경사도를 측정하는 화면입니다.

평균경사도는 인허가 업무에 매우 중요한 변수인데요. 관련 법률에 따라 특정 경사도 이하에서만 인허가 승인이 결정되기 때문입니다.

이번 글에서는 넥스젠의 기본기능 중 2가지에 대해서만 소개했는데요. 추후 기회가 있다면 다른 기능도 소개하도록 하겠습니다.

공개소스트웨어인 넥스젠은 이미 개발되어진 기본 기능 위에 사용자가 필요로 하는 기능을 추가할 수 있도록 설계된 웹 기반의 GIS 소프트웨어입니다.

넥스젠에 대한 다른 기능에 대한 실제 시연을 보고자 하시는 분은 메일(hjkim@geoservice.co.kr)을 통해 문의해 주시면 됩니다.