신주소(도로명 주소) 체계

도로명을 중심으로 표기되는 새로운 주소 체계가 2014년부터 본격적으로 의무화되어 시행됩니다. 잘쓰고 있는 지번 주소를 왜 버리고 도로명 주소를 쓰느냐라고 불평할 수 있도 있으나 지금 세대가 아닌 미래의 후손을 위한 것이므로 긍정적으로 생각됩니다.

이 글은 개발자로써 바라본 신주소 체계에 대한 정리입니다. 이를 정리한 이유는 사용자가 자유롭게 입력한 신주소에 대해서 부분(Part) 별로 분리해 내기 위해서, 먼저 신주소 체계를 이해하고 각 부분을 분리해 내기 위해서 필요한 각 부분의 규칙성을 파악하기 위함입니다. 먼저 신주소는 다음과 같은 최대 7개로 구분됩니다.

사용자 삽입 이미지
이들에 대해서 각기 갖는 특징을 정리해 보면 다음과 같습니다.

사용자 삽입 이미지이 부분은 ‘시’, ‘도’로 끝납니다. 그리고 축약된 형태가 많이 사용되는데, 예를 들어서 서울특별시의 경우 서울로, 전라북도를 전북으로 표기되는 경우가 많습니다. 이 부분은 모두 한글로 구성됩니다.

사용자 삽입 이미지이 부분은 ‘시’, ‘군’, ‘구’로 끝납니다. 2개의 단어로 구성된 경우가 있는데, 예를 들어서 ‘수원시 영통구’와 ‘전주시 덕진구’ 등이 있습니다. 이렇게 2개의 단어로 구성되는 경우 2번째 단어는 ‘구’로 끝나게 됩니다. 이 부분은 모두 한글로 구성됩니다.

사용자 삽입 이미지이 부분은 ‘읍’, ‘면’으로 끝납니다. 한글로만 구성됩니다. 새주소에서는 이 부분이 자주 생략되는 특징이 있습니다.

사용자 삽입 이미지이 부분은 ‘로’, ‘길’로 끝납니다. 숫자와 한글로 구성될 수 있습니다.

사용자 삽입 이미지이 부분은 건물의 번호로써, 본번만 있을 경우 숫자로만 구성됩니다. 부번이 있을 경우 본번과 부번의 구분을 위해 ‘-‘가 사용됩니다.

사용자 삽입 이미지이 부분은 건물 번호 다음에 위치하므로 반드시 숫자 다음에 명시됩니다. 건물 번호와 구분을 위해 ‘,’가 사용되지만 입력자의 부주의로 인해 생략되기도 합니다. 건물의 ‘동’, ‘호’, ‘층’에 대한 내용이 옵니다. 한글, 영문, 숫자 등 다양하게 기재될 수 있습니다. 해당 내용의 정확한 구분을 위해 ‘동’, ‘호’, ‘층’으로 명시됩니다.

사용자 삽입 이미지이 부분은 중가로 열기 ‘(‘로 시작하여 중가로 닫기 ‘(‘로 끝납니다. 자주 변경되는 행정동이 아닌 법정동과 해당 주소의 건물이 공동 주택일 경우 공동주택명이 나타납니다. 법정동과 공동주택명 모두가 표시될때는 ‘,’로 구분됩니다.

psql에서 INSERT 문 실행시 한글 문제

postgreSQL의 콘솔인 psql에서 직접 SQL문을 던져서 테이블을 생성하고 데이터를 INSERT할때 한글 데이터에서 INSERT 문의 실행 조차 되지 않는 문제는 postgreSQL에 대한 서버 측과 클라이언트 측의 한글 처리 방식(인코딩)이 다르기 때문입니다. 만약 서버 측의 인코딩 방식이 UTF8이라면 클라이언트 측의 인코딩도 UTF8로 변경해야 합니다. 방법은 콘솔에서 다음처럼 입력하면 됩니다.

set client_encoding = 'UTF8';

이렇게 하고 한글 데이터를 가진 INSERT 문을 실행하면 잘들어갑니다. 그리고 SELECT 문을 통해 확인해 보면 제대로……. 가 아닌 한글이 깨져 보입니다.

사용자 삽입 이미지
뭐가 문제인지 기본으로 돌아가 생각해보면… 먼저 psql 콘솔에서 SQL 문은 외부 파일을 통해 다음처럼 실행합니다.

\i c:/insert.sql

그런데 이 insert.sql 파일은 C#으로 만든 것이고.. 혹시 C#에서 이 파일을 생성할 때 인코딩 지정 문제로 생각하여 UTF8로도 해보고 EUC-KR로도 인코딩 해보았으나 모두 깨지고.. 여차 저차 결국 인코딩 없이(그럼 이건 어떤 인코딩이지?) 그냥 저장하도록 다시 원복하고 GUI 툴인 pgAdmin에서 해당 데이터를 보니 한글이 않깨져 있습니다.
사용자 삽입 이미지
결론은 한글이 제대로 저장된 것이고 콘솔에서 한글이 깨져 표시되는 것이였습니다. 일단 Windows에서는 한글 데이터 저장은 되었는데.. 실제 구동은 리눅스에서 하는데 거기에도 또 다른 한글 문제가 흐물 흐물 기다리고 있을 듯 한데.. 걱정입니다.. 일단 작업은 Windows에서 하고.. 최종 배포에서 나타날 한글 괴물 보스에게 빌어야 겠네요…

참고로 psql의 출력결과를 파일로 내보내기 위해서 다음 명령을 수행하면 됩니다.

\o c:/log.txt

이때 psql을 관리자 권한으로 실행해야 합니다.

VWorld의 WMS 지도 서비스

VWorld에는 TMS 방식의 다양한 배경지도(단순 배경지도와 항공영상 지도 등) 뿐만이 아니라 유용한 WMS 방식의 지도 서비스도 제공하고 있습니다. 이를 VWorld에서 OpenAPI 키를 발급받아 TMS나 WMS를 지원하는 OpenLayers나 FingerEyes와 같은 클라이언트 맵엔진에서 사용할 수 있습니다.

이 글은 VWorld에서 제공하는 WMS 지도 서비스를 이용하는데 필요한  WMS 파라메터에 대해 정리한 글입니다. 저는 제게 익숙한 FingerEyes를 이용해 VWorld의 WMS 지도 서비스를 살펴보았습니다. OpenLayers에 익숙하다면 쉽게 적용이 가능할 것으로 판단됩니다. 참고로 VWorld는 자체적인 2D Map API를 지원하고 있으므로 이를 이용할 수도 있습니다.

먼저 자연환경 보전 지역에 대한 WMS 지도 서비스 요청입니다. 참고로 _KEY_KEY_라고 되어 있는 부분은 VWorld에서 직접 OpenAPI Key를 발급받아 지정하시면 됩니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_C_UQ114", 
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

그 결과에 대한 지도는 아래와 같습니다. 참고로 배경맵은 VWorld의 TMS 지도 서비스를 사용하였습니다.

사용자 삽입 이미지
다음은 개발제한구역에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_C_UD801", 
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

결과는 아래와 같습니다.

사용자 삽입 이미지
그리고 다음은 지적도에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LP_PA_CBND_BUBUN%2CLP_PA_CBND_BONBUN", 
    "EPSG:900913");

    map.layers.addLayer(wmsLayer);

결과는 아래와 같습니다.

사용자 삽입 이미지
그리고 다음은 새주소도로에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_L_SPRD",
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

결과는 아래와 같습니다. 참고로 새주소도로는 도로 위의 도로명에 대한 표시입니다.

사용자 삽입 이미지   
그리고 다음은 토지이용계획도에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_C_LHBLPN", 
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

결과는 다음과 같습니다.

사용자 삽입 이미지
그리고 다음은 국토계획구역에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_C_UQ141",   
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

결과는 다음과 같습니다.

사용자 삽입 이미지
그리고 다음은 사업지구경계도에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_C_LHZONE", 
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

다음은 그 결과입니다.

사용자 삽입 이미지
그리고 다음은 도시지역도에 대한 WMS 지도 서비스 요청입니다.

var wmsLayer:XrWMSLayer = new XrWMSLayer("wms", 
    "http://2d.vworld.kr:8895/2DCache/gis/map/WMS2?APIKEY=_YOUR_KEY_&", 
    "LT_C_UQ111", 
    "EPSG:900913");

map.layers.addLayer(wmsLayer);

결과는 다음과 같습니다.

사용자 삽입 이미지
이외에도 향후 더 다양한 WMS 지도 서비스를 제공할 것으로 생각됩니다. 이처럼 국가에서 제공하는 양질의 유용한 지도 데이터 서비스를 활용하여 민간업체에서 더 나은 서비스를 연구 및 기획하여 실제 개발할 수 있을 것입니다.

실습강의자료 ㅡ 스마트기기융합서비스개발

경일대의 공간정보공학과에서 진행한 모바일 GIS 실습자료입니다. 모바일 GIS 엔진인 블랙포인트를 이용하여 실습을 진행하였습니다. 다음과 같은 내용을 중심으로 실습을 하였습니다.

  1. 스마트 폰 또는 태블릿 PC의 화면에 지도를 표시하고
  2. 지도를 레이어(Layer) 단위로 구성하며
  3. 구성된 레이어의 색상 등의 심벌을 지정하고
  4. 구성된 레이어의 라벨을 표시하며
  5. 표시된 건물을 터치하면 터치된 건물의 속성 정보를 제공하고
  6. 현재 내 위치로 지도를 이동함

아래의 이미지는 최종 실습 결과물에 대한 실행화면 예시입니다.

사용자 삽입 이미지

그리고 아래는 실습을 위한 수업자료입니다.

반복문의 반복 횟수를 줄이는 코드 작성

반복문의 속도를 최적화하기 위한 방법중의 하나로 반복 횟수를 줄이는 것이 있습니다. 이에 대해서 제프 그린버그(Jeff Greenberg)가 제안한 내용이 있는데요. 처음 제안될때 작성된 샘플 코드가 C이지만 이를 JavaScript로 해석해 보았습니다. 먼저 개선해 나갈 반복문의 코드가 다음과 같습니다.

function task(arg) {
    var sum = 0;
    for (var i = 0; i < 10; i++) {
        sum += i;
    }
    return sum;
}

var start = +new Date();
var result = 0;
var repeatCounts = 9999999;

//========================================
for (var i = 0; i < repeatCounts; i++) {
    result += task(i);
}
//========================================

var end = +new Date();
var diff = end - start;
alert("result = " + result + ", " + diff + " msec");

최적화 대상이 되는 반복문은 13ㅡ17번입니다. 반복문 안에서 실해된 코드를 별도의 함수인 task로 뽑아놨습니다. task는 1부터 10까지의 합계를 구하는 간단한 연산을 수행하는 함수입니다. 반복문의 속도를 측정하기 위해서 반복문 앞뒤로 시간을 측정하고 있습니다. 이 반복문을 수행하였더니 제 타블릿PC에서는 8.6초가 나왔습니다. 이제 동일한 결과를 얻으면서도 반복 회수를 줄이는 방식으로 최적화를 한 코드는 다음과 같습니다. 위의 13ㅡ17번에 대한 반복 코드에 대한 변경된 부분만 언급하였습니다.

//========================================
var iters = Math.floor(repeatCounts / 10);
var startAt = repeatCounts % 10;
var i = 0;

do {
    switch (startAt) {
        case 0: result += task(i++);
        case 9: result += task(i++);
        case 8: result += task(i++);
        case 7: result += task(i++);
        case 6: result += task(i++);
        case 5: result += task(i++);
        case 4: result += task(i++);
        case 3: result += task(i++);
        case 2: result += task(i++);
        case 1: result += task(i++);
    }
    startAt = 0;
} while (iters--);
//====================================

한번의 반복으로 최대 10번의 반복을 대신하고 있습니다. switch 문을 보면 break문이 없다는 점을 유념해 해석해 보면 그 원리를 이해할 수 있습니다. 실행해 보면 소요되는 시간이 6.3초로 2.4초 단축된 것을 알 수 있습니다.