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

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

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

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

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

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

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

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

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

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

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

DuraMap-Xr에서 고정값으로 라벨 회전

라벨을 일정한 값으로 회전하는 API에 대한 내용을 정리합니다. 아래는 해당 코드입니다.

if(axXr1.Layers.AddShapeMapLayer("lyr", "d:/_/ecl_cadastral.shp"))
{
    axXr1.WaitForAllConnections();

    axXr1.Labels.AddLabel("lyr", "{label}");
    
    var label = axXr1.Labels.GetLabel("lyr", "{label}");

    label.Rotate.Enable = true; // <회전을 위해 반드시 지정해야 함>
    label.Rotate.Angle = 90; // <회전값, 단위: Degree>
    label.Effect.Enable = true; // <회전을 위해 반드시 지정해야 함>
    label.Effect.OutlineEnable = true;
    label.Effect.OutlineColor = RGB(255, 255, 255);
    label.Effect.OutlineWidth = 3;
    label.Font.Bold = true;
    label.Font.Color = RGB(0, 0, 0);
    label.Font.Size = 16;

    axXr1.ZoomFullExtent();
    axXr1.MapScale = 2500;
    axXr1.MouseMode = XrMapLib.XrMapViewModeEnum.XrPanMode;
    axXr1.Update();
}

위의 코드는 모든 라벨의 텍스트를 일정하게 90도로 회전하는 코드인데요. 아래는 위의 코드에 대한 실행 결과입니다.

위의 코드가 지원되는 DuraMap-Xr의 버전은 3.9.8.4입니다. 듀라맵의 최선 버전은 http://www.gisdeveloper.co.kr/?p=4760 에서 다운로드 받을 수 있는 설치관리자 프로그램을 이용해 간단히 설치할 수 있습니다.

pl/pgsql을 이용한 테이블 업데이트(Update)

기존의 테이블에 새로운 필드를 추가하고, 이 필드에 값을 넣어야 할 필요가 있습니다. 상황은 지적도가 저장된 테이블의 PNU 필드를 파싱해서 번지값을 만들어 저장해야 합니다. 예를 들어서 PNU가 ‘2911011200200470001’라면 ’47-1산’으로 만들어야 한다는 것입니다.

사용하는 데이터베이스가 PostgreSQL이므로 pl/pgsql을 이용하였는데요. cursor를 이용하는 방식과 cursor를 이용하지 않는 방식이 있는데.. 먼저 cursor를 이용하지 않는 방식은 아래와 같습니다.

DO $$
DECLARE
    r RECORD;
    n1 INTEGER;
    n2 INTEGER;
    s TEXT;
    v TEXT;
BEGIN
    FOR r IN SELECT * FROM ecl_cadastral LOOP
        n1 = substr(r.pnu, 12, 4)::INTEGER;
        n2 = substr(r.pnu, 16, 4)::INTEGER;
        s = substr(r.pnu, 11, 1);
        
        IF n2 = 0 THEN
            v = n1;
        ELSE
            v = n1 || '-' || n2;
        END IF;

        IF s = '2' THEN
            v = v || '산';
        END IF;

        UPDATE ecl_cadastral SET label = v WHERE fid = r.fid;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

동일한 기능으로 cursor를 이용하는 방식은 아래와 같습니다.

DO $$
DECLARE
    c CURSOR FOR SELECT * FROM ecl_cadastral;
    r RECORD;
    n1 INTEGER;
    n2 INTEGER;
    s TEXT;
    v TEXT;
BEGIN
    FOR r IN c LOOP
        n1 = substr(r.pnu, 12, 4)::INTEGER;
        n2 = substr(r.pnu, 16, 4)::INTEGER;
        s = substr(r.pnu, 11, 1);
        
        IF n2 = 0 THEN
            v = n1;
        ELSE
            v = n1 || '-' || n2;
        END IF;

        IF s = '2' THEN
            v = v || '산';
        END IF;

        UPDATE ecl_cadastral SET label = v WHERE CURRENT OF c;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

속도는 cursor를 이용하는 방식이 약 20% 정도 빨랐습니다.

FingerEyes-Xr for HTML5의 레이어 추가시 연결 완료 이벤트

FingerEyes-Xr에서 레이어를 추가하기 위한 매서드는 LayerManager의 add 입니다. 이 add 매서드는 2개의 인자를 받는데요. 첫번째는 추가하고자 하는 Layer 객체이고 두번째는 선택 사항으로 추가하려는 레이어가 네트워크를 통해 성공적으로 연결되었을 때 호출할 callback 함수입니다. 이 callback 함수는 레이어 추가시 개별적으로 세밀한 흐름 제어를 위해 사용됩니다. 이와 관련한 예는 아래와 같습니다.

var baseLyr = new Xr.layers.TileMapLayer(layerName,
    {
        url: "http://localhost/....",
        ext: "jpg"
    }
);

var lm = map.layers();

lm.add(baseLyr, 
    function (lyr) {
        lm.moveToFirst(layerName);
        map.updateLayer(layerName);
    }
);

위의 코드는 배경지도를 새롭게 추가할 때 추가된 레이어를 가장 첫번째 순위로 이동하고 추가된 레이어만을 새롭게 화면상에 업데이트하라는 코드입니다. 이러한 코드는 해당 레이어가 네트워크를 통해 완전히 연결된 이후에 실행되어야 하는 코드이므로 callback 함수의 사용에 적합합니다.