FingerEyes-Xr의 DeferableShapeDrawTheme 추상 클래스

FingerEyes-Xr for HTML5는 DeferableShapeDrawTheme 추상 클래스를 제공합니다. Deferable은 “미룰 수 있는”이라는 의미인데요. 수치지도 레이어를 그리기 위한 심벌의 지정을 미룬다는 의미입니다. 이 추상 클래스는 상속 받아 구현해야 하는 매서드는 /* void */ requestCondition: function (/* int */fid)입니다. 이 클래스의 목적에 대한 설명은 잠시 미루고 이 클래스를 상속받아 만든 예로써 MyDeferableShapeDrawTheme 클래스는 아래와 같습니다.

MyDeferableShapeDrawTheme = Xr.Class({
    name: "MyDeferableShapeDrawTheme",
    extend: Xr.theme.DeferableShapeDrawTheme,

    construct: function() {
        this.superclass();

        this._ON_sds = new Xr.symbol.ShapeDrawSymbol();
        this._ON_sds.markerSymbol(new Xr.symbol.ImageMarkerSymbol(
            { width: 16, height: 16, url: "images/gis/facility/OH_SW_ON.png" }));

        this._OFF_sds = new Xr.symbol.ShapeDrawSymbol();
        this._OFF_sds.markerSymbol(new Xr.symbol.ImageMarkerSymbol(
            { width: 16, height: 16, url: "images/gis/facility/OH_SW_OFF.png" }));
    },

    methods: {
        /* void */ requestCondition: function (fid) {
            var that = this;
            var sql = "SELECT swstatcd FROM ecl_sw_p WHERE fid = " + fid;
            var url = mg_MapLayers.GIS_HTTP_SERVER + "/Xr?sql|" + encodeURIComponent(sql) + "|mg_db|1"

            $.ajax({
                url: url,
                dataType: "text",
                type: "GET",
                statusCode: {
                    200: function (response) {
                        // response 문자열 끝에 \0 문자를 제거
                        response = response.substr(0, response.length - 1); 

                        var result = JSON.parse(response);
                        if (result.length == 1) {
                            if (result[0]["swstatcd"] === "ON") {
                                that.setSymbol(fid, that._ON_sds);
                            } else {
                                that.setSymbol(fid, that._OFF_sds);
                            }
                        }                        
                    }
                }
            });            
        }
    }
});

위의 코드는 순수한 Javascript 코드이며, FingerEyes-Xr 방식의 클래스 정의입니다. 위의 코드에서 보이는 것처럼 3번 코드에서 Xr.theme.DeferableShapeDrawTheme 클래스는 확장한다고 명시되어 있고, 18번 코드에서 requestCondition 매서드를 구현하고 있습니다. 5번 코드가 생성자 함수인데요. 이 생성자에서는 2개의 이미지 심벌을 정의하고 있습니다. 이 2개의 이미지 심벌은 설비 따위에 대한 상태값으로 ON 상태의 이미지와 OFF 상태의 이미지를 나타냅니다. 이렇게 정의된 심벌은 18번 코드의 매서드인 requestCondition에서 사용되는데요. 이 requestCondition은 이름 그대로 “조건을 요청한다”라는 매서드로 그 구현 코드를 보면 어떤 SQL문을 서버측에 요청하고 있습니다. 그 요청 결과는 JSON으로 받게 되는데요. 34~38번 코드에서처럼 JSON 결과 중 swstatcd 필드의 값이 ON일때와 그 외의 값일때에 대해 setSymbol 매서드를 호출해 표현할 심벌을 지정해 줍니다.

이렇게 정의된 MyDeferableShapeDrawTheme 클래스는 수치지도 레이어를 생성하고 추가할때 사용되는데요. 아래의 예와 같습니다.

var lyr = new Xr.layers.ShapeMapLayer(layerId, ...);
lyr.deferableTheme(new MyDeferableShapeDrawTheme());

이해를 돕고자 위의 코드가 적용된 실행 결과에 대한 지도 화면은 다음과 같습니다.

위의 지도 화면에서 파랑색의 ON 아이콘과 빨간색의 OFF 아이콘 심벌이 위의 코드를 통해 반영된 심벌 결과입니다.

그렇다면 이 클래스의 제공하는 이유는 무엇일까요? 일반적으로 GIS의 DB 구조를 살펴보면 공간 데이터와 속성 데이터가 동일한 DBMS의 동일한 Database 내에 존재하게 됩니다. 그러나 전체 시스템이 커지거나, 타 시스템와의 연계가 필요할 경우 도형 데이터와 속성 데이터가 전혀 다른 DBMS로 분리 구분되어 저장됩니다. 바로 이러한 환경에서도 공간 데이터와 다른 DBMS의 속성 데이터가 접목되어 유연하게 조합되어 활용될 수 있도록 하기 위해 제공되는 클래스가 바로 DeferableShapeDrawTheme입니다.

끝으로, ShapeDrawSymbol 클래스를 통한 심벌 정의 시에 Brush와 Pen에 대한 심벌의 정의 예는 아래와 같습니다.

this._ON_sds = new Xr.symbol.ShapeDrawSymbol();
this._sds.brushSymbol(new Xr.symbol.BrushSymbol({ color: 'red' }));
this._sds.penSymbol(new Xr.symbol.PenSymbol({ color: 'yellow', width: 2 }));
this._ON_sds.markerSymbol(new Xr.symbol.ImageMarkerSymbol(
    { width: 16, height: 16, url: "images/gis/facility/OH_SW_ON.png" }));

EUC-KR로 인코딩된 속성값이 깨진 SHP, DBF 파일 복구하는 프로그램

국내에서 사용되는 거의 대부분의 SHP 파일의 속성 데이터는 EUC-KR로 인코딩되어 있습니다. 이러한 SHP 파일을 PostgreSQL에 테이블로 Importing 하기 위해 Shapefile Import/Export Manager와 같은 툴을 사용하게 되는데요. 가끔 다음과 같은 에러를 출력하고 Importing이 실패하게 됩니다.

물론 위의 Shape Import/Export Manager 툴에서 SHP 파일을 Importing 할때 문자셋을 EUC-KR로 명확히 지정한 경우입니다. 이 경우 DBF 파일에 저장된 한글 문자열은 분명히 EUC-KR로 인코딩되어 있으나 깨졌거나.. 기타 여러가지 이유가 그 원인이 될 수 있습니다. 대부분의 프로그램에서는 데이터가 조금 깨져 있어도 읽는데 있어 위의 경우처럼 문제를 발생하지 않습니다. 왜냐하면 깨진 문자열이 그다지 중요하지 않은 경우가 많기 때문입니다.

이러한 상황에서 옳바르게 SHP 파일을 Importing 해 줄 수 있는 툴을 소개합니다.

매우 단순한 UI를 갖는 이 툴은 문제가 있는 SHP 파일을 문제가 없도록 만들어 주는 툴입니다. 혹 저와 동일한 문제로 인해 작업 시 어려움을 격는 분이 있다면 이 툴을 사용해 보시기 바랍니다. 아래 실행 파일을 첨부합니다.



이 프로그램은 DuraMap-Xr을 사용합니다. 실행 전에 DuraMap-Xr을 설치하셔야 하는데요. 다음 URL에서 소개하는 설치자를 통해 매우 간단히 설치할 수 있답니다.

DuraMap-Xr 설치자

GeoService-Xr에서 DEM Dataset을 활용한 서비스

GeoService-Xr에서 DEM Dataset을 활용한 서비스는 크게 3가지입니다. 첫번째는 원하는 지점에 대한 높이값을 얻기, 두번째는 지정된 경로에 대한 횡단면도(Cross Section)을 구성하는 연속된 표고값 얻기, 세번째는 지정된 영역에 대한 평균경사도 얻기 입니다.

첫번째 서비스로, 원하는 지점에 대한 높이값을 얻는 예로써.. 다음처럼 간단한 URL 호출을 통해 서비스를 실행하고 그 결과를 XML 형태로 받을 수 있습니다.

http://127.0.0.1:8080/Gp?command=z;dem=DEM;h=117658.41;v=250496.85

두번째 서비스로, 지정된 경로를 WKT 형식으로 Polyline으로 구성하고 해당 경로에 대한 횡단면도에 대한 결과를 얻는 예로써, 역시 아래의 URL 호출을 통해 쉽게 서비스를 실행할 수 있습니다.

http://127.0.0.1:8080/Gp?command=crosssection;dem=DEM;geometry=MULTILINESTRING((154262.32 265274.12, 164262.32 265274.12))

세번째 서비스로, 지정된 영역을 WKT 형식인 Polygon으로 구성하여, 해당 영역에 대한 평균 경사도를 분석하는 예로써, 아래의 URL 호출을 통해 서비스를 실행합니다.

http://127.0.0.1:8080/Gp?command=slope;dem=DEM;geometry=POLYGON((154262.32 265274.12, 164262.32 265274.12, 164262.32 275274.12, 154262.32 275274.12, 154262.32 265274.12))

각각의 서비스 결과는 XML 형식인데요. 최종적으로 사용자에게 서비스 결과를 제공할때는 그래픽적으로 효과적으로 시각화하여 제공하는 것이 좋을 것입니다.

GeoService-Xr에서 DEM Dataset 올리기

공간 서버인 GeoService-Xr에서 DEM 데이터는 XrE라는 포맷으로 관리됩니다. 흔히 flt나 xyz, dem와 같은 확장자로 규정된 파일을 XrE 포맷으로 먼저 변환할 필요가 있습니다. 이렇게 변환된 XrE 파일을 특정 디렉토리에 저장해 두고 geodata.xml 파일에 다음과 같이 정의해 둡니다.

<?xml version="1.0" encoding="euc-kr"?>
<XrGeoData>
    <Connections>
    </Connections>

    <GeoDataList>
        <GeoData>
            <Name>GDN_DEM</Name>
            <ConnectionString>xre://D:/__Data__/DEM_TEST</ConnectionString>
        </GeoData>
    </GeoDataList>
</XrGeoData>

위의 예는 XrE 파일들이 D:/__Data__/DEM_TEST 디렉토리에 존재하는 것이고, 이 XrE 파일들은 하나의 DEM 데이터셋으로써 GDN_DEM으로 이름을 정하고 있습니다. 이렇게 DEM 데이터를 서비스할 준비가 되면 GeoService-Xr에서 평균경사도나 횡단면도 그리고 특정 지점에 대한 표고값을 사용자에게 서비스할 준비가 완료됩니다. 실제 GeoService-Xr에서 위에서 설정한 내용에 대한 geodata.xml이 성공적으로 적재되면 다음과 같은 내용이 출력되고, 서비스할 준비가 완료됩니다.

geodata building start
    DEM building ...
        D:\__Data__\DEM_TEST/34601.XrE building ... OK
        D:\__Data__\DEM_TEST/34602.XrE building ... OK
        D:\__Data__\DEM_TEST/34603.XrE building ... OK
        D:\__Data__\DEM_TEST/35613.XrE building ... OK
        D:\__Data__\DEM_TEST/35614.XrE building ... OK
        D:\__Data__\DEM_TEST/35615.XrE building ... OK
geodata building end

참고로, XrE 파일은 최대한 사각형 모양으로 클리핑되어 구성 되어야 하며, 영역은 알맞은 정도로 작게 잡아야 합니다. GeoService-Xr로 로딩할 수 있는 XrE에 대한 파일 크기 및 개수에는 제한없이 없지만 속도적인 측면에서 하나의 XrE 파일이 포함하는 지형 영역을 작게 잡아야 한다는 점에 주의해야 합니다.

DuraMap-Xr에서 Image Symbol 크기 조정

듀라맵에서 ShapeMapLayer에 대한 이미지 심벌을 지정할 경우에, 그 크기는 원본 이미지 크기 그대로 표시됩니다. 이에 대해 개발자가 직접 이미지의 크기를 지정할 수 있는 방식도 제공되는데요. 아래의 코드는 이미지의 크기를 가로 84px로 지정하는 경우입니다. 세로의 크기는 가로와 세로에 대한 비율을 유지하도록 자동으로 계산됩니다.

axXr1.Layers.AddShapeMapLayer("lyr", "D:/__Data__/points.shp");
axXr1.WaitForAllConnections();

if (axXr1.Resources.AddImageResource("img", "d:/__data__/temperature.png"))
{
    var sym = axXr1.Layers.GetLayerAsShapeMap("lyr").PointSymbol;

    sym.SetImage("img", axXr1.Resources);
    sym.Size = 84; // 이미지 심벌을 가로로 84px로 지정 !!
}

axXr1.Update();

위의 코드와 함께 듀라맵에 소소한 개선으로 두가지가 이루어졌는데요. 첫째는 휠마우스에 대한 Delta 값을 보다 정확히 음수와 양수로 얻을 수 있다는 것과 두번째는 GetFIDFromMousePoint 매서드를 통해 도형을 선택할 때, 포인트 심벌의 크기에 맞춰 선택할 수 있도록 개선되었는데요. 기존에는 포인트 심벌의 크기를 고려하지 않아 포인트의 심벌 중앙을 클릭해야 선택되는 사용상의 불편함이 해소되었습니다.