개요

스마트시티, 디지털 트윈 등 실세계를 가상공간으로 구현하고자 하는 다양한 시도가 이루어지고 있습니다. 그러나 정교한 가상공간을 만드는 일은 상당한 자원과 시간이 소요됩니다. 물론 구축 후 얻게되는 가치는 추정하기 어려울 정도로 클 것으로 예상됩니다. 

프로그웍스는 현재 개방되는 데이터를 가지고 제한적이지만 이의 구현이 가능할 지 확인해 봤습니다. 그래서 국가공간정보포털 오픈마켓을 통해 "건물통합정보"를 다운받아 특정 지역(경기도 성남시 중원구 성남동)의 3D 건물모델을 만들었습니다. 그러나 역시 문제는 원본 데이터의 품질 문제 입니다. 예를 들면 건물의 고도 값이 0 인 것도 많이 존재하고, 층수도 0인것, 지하층수가 0인 것도 있습니다. 신뢰성에 큰 문제가 있습니다.

당연히 제작되는 결과물도 원본 품질에 종속적일 수 밖에 없습니다. 제작한 결과물의 정교함이 아닌 PostGIS를 이용하는 한 가지 사례로써 봐주십시오.

제작 과정

 1. 대상 지역 추출 (경기도 성남시 중원구 성남동)

읍면동코드를 이용하여 성남동 경계에 포함되는 건물을 추출합니다. 이 때 ST_GeometryN 함수를 이용하여 멀티폴리곤에서 첫 번째 폴리곤만을 추출합니다. (멀티폴리곤이지만 대부분 하나의 폴리곤만 존재합니다)
PostGIS 3d 변환 함수는 단일파트 형식 Geometry만을 지원합니다.

create table tmp_m41130_002_01 as
  with bound as
   (select geom as geom2 from n3a_g0110000 where bjcd = '4113310100')
  select bd.bld_nm, bd.dong_nm, bd.grnd_flr, bd.ugrnd_flr, bd.height, bd.geom from  
  (select bld_nm, grnd_flr, ugrnd_flr, height, ST_GeometryN(geom, 1) as geom from m41130_002_1) bd, bound  

    where st_intersects (bd.geom, bound.geom2) = true;

2. 3D 데이터 생성을 위한 투영좌표계 변환

x, y, z 로 표현되는 형식의 단위 값을 같아야 합니다. Degree 형식의 경위도 좌표는 정확한 높이 값 적용이 어렵습니다. 이에 Linear Unit이 m (미터)를 이용하는 투영좌표계(TM)를 이용하고, 저희는 구글좌표계로 변환했습니다.
( 참고 바로가기 : PostGIS에서 공간테이블 좌표 변환 )

ALTER TABLE tmp_m41130_002_01
  ALTER COLUMN geom TYPE geometry(Polygon,3857) USING ST_Transform(ST_SetSRID(geom,4326), 3857);

3. 3D 건물데이터 생성

ST_Extrude 함수를 이용하여 3D 형식 Geometry로 변환합니다. 이 때 Z(높이 값) 적용을 위하여 건물통합 데이터의 "height"속성을 이용하려 했으나 0인 것이 많아 임의로 "grnd_flr(지상층)" 속성에 3.5m 를 곱한 것으로 대체했습니다. 물론 "grnd_flr"속성에도 0인 것이 많아 정확하게 만들어지지는 않습니다.
실제 Query 수행 후 생성된 ST_GeometryType 함수를 이용하여 생성된 Geometry가 "ST_PolyheralSurface" 형식으로 변경된 것을 볼 수 있습니다.

-- 3D 테이블 생성
create table m41130_002_3d as

  select bld_nm, grnd_flr, ugrnd_flr, height,  ST_Extrude(geom, 0, 0, grnd_flr * 3.5) as geom from tmp_m41130_002_01;

-- Geometry 형식 검사
select ST_GeometryType(geom) as gtype from m41130_002_3d limit 1;

4. 데이터 조회

QGIS 에서 PostGIS를 연결한 후 생성된 테이블을 레이어로 추가합니다. 레이어는 "보기 > 새 3D 맵뷰"에서 볼 수 있습니다. 

<QGIS를 이용한 3D 건물 조회>

맺음 말

저희가 게시하는 사용 팁은 오랜 기간의 경험을 통해 얻어진 지식입니다. 정말 자신의 것이 되기 위해서는 공개SW 제작사의 공식 매뉴얼을 통해 함수를 사용하기 위한 제약조건 등의 확인이 필요합니다. 또한 눈으로 얻어지는 것은 없습니다. 실제 해보는 것이 중요합니다. 저희가 게시하는 주제 및 샘플은 공개SW와 공공 개방되는 데이터를 이용하여 제작됩니다. 약간의 수고를 통해 필자의 오랜 노하우를 쉽게 가질 수 있습니다.

언제가는 좋아지겠지만 개방되는 공간정보의 품질이 좋아지기를 간절히 바랍니다. 이 부분이 해결된다면 얻을 수 있는 것이 참 많을 것 같습니다. 

이번시간에는 Qgis를 통해 구축한 3D 건물데이터를 Cesium JS를 통해 맵 상에 구현해보도록 하겠습니다.
결과화면 보겠습니다.


서비스바로가기

먼저, Qgis를 통해 데이터를 생성하도록 하겠습니다. 
활용 데이터 : 국가공간정보포털 - 건물통합정보마스터 (업로드 용량제한으로 인해 예제파일을 첨부 못하는 점 양해바랍니다.)

데이터 중 여의도 지역만 추출하도록 하겠습니다. 
추출 방법은 다음과 같습니다. 

shift키를 누른 채 마우스 클릭 및 끌기를 하여 지역을 다중선택 합니다.

레이어 트리에서 해당 레이어를 "선택한 객체를 다른이름으로 저장"으로 저장합니다. (좌표계는 EPSG:4326)

플러그인을 이용해 추출한 여의도 지역을 3D로 변환시켜보겠습니다.
먼저, Qgis2threejs 플러그인을 설치해주세요. 설치 후 플러그인을 실행시킵니다.

앞서 추출하였던 여의도 지역이 3D로 변환된것을 볼 수 있습니다.

해당 레이어를 우클릭하여 properties를 연 후, 옵션을 설정합니다. 필자는 아래와 같이 설정하였습니다.

옵션 설정 후 그림과 같이 레이어를 GLTF 포맷으로 저장합니다. (Cesium JS는 기본적으로 GLTF 포맷을 사용합니다.)

 

이제 Cesium JS에 데이터를 적용시켜보겠습니다. 

데이터를 올렸지만 위와 같은 현상이 발생했습니다.

여기서 필자는 2가지 방법을 활용하여 데이터의 위치를 조정할 수 있었습니다.

* Cesium ION 활용


Cesium ION 사이트에 접속 후 Add data 버튼을 눌러 여의도 데이터를 Upload합니다.

Upload 버튼을 누릅니다.

업로드가 완료된 데이터를 확인하니 Tileset의 위치가 설정되어있지않다는 문구가 표출됩니다.
데이터 화면 위에 Adjust Tileset Location 버튼을 눌러 데이터의 위치 및 옵션을 설정해야 합니다.

도구들을 통해 설정을 해주도록 합니다.
search를 통해 데이터를 위치시켜주고 Rotation 메뉴를 통해 데이터의 방위를 맞춘 후 Scale을 통해 데이터의 크기를 설정하여 줍니다.
그리고 데이터에 위치해있는 파랑, 빨강, 초록선들을 활용하여 세부 위치를 조절합니다.

파란선은 높이를 빨간선과 초록선은 X, Y축이라 생각하시면 됩니다. 설정 후 Save 버튼을 눌러 저장 및 완료 합니다.

Cesium ION에서 작업 한 데이터를 맵 상에 올려보겠습니다. 사용한 소스코드는 아래와 같습니다.

var position = Cesium.Cartesian3.fromDegrees(126.926094, 37.526077, 0);

var tileset = viewer.scene.primitives.add(
	new Cesium.Cesium3DTileset({
		url: Cesium.IonResource.fromAssetId(*****),
		position : position
	})
); 

실행 화면입니다.

3D 건물이 맵 상에 표출된 모습입니다.

 

* 소스코드상에서 3D 모델의 위치를 조정

var headingPitchRoll = new Cesium.HeadingPitchRoll();
var fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator('south', 'east');

var model = scene.primitives.add(Cesium.Model.fromGltf({
	url : 'js/image/test.gltf',
	modelMatrix : Cesium.Transforms.headingPitchRollToFixedFrame(position, headingPitchRoll, Cesium.Ellipsoid.WGS84, fixedFrameTransform),
	scale : 37.5
	})
);

localFrameToFixedFrameGenerator 함수를 사용하였습니다.

요약하자면 원점의 프레임을 기준으로 firstAxis, secondAxis를 참고하여 프레임을 변환한다는 의미입니다.
firstAxis와 secondAxis의 의미는 east, north는 올리고 west, south는 내린다는 말로 둘의 설명이 같습니다.
즉, firstAxis와 secondAxis의 값에 따라 프레임의 위치가 변경되는 것입니다.

실행화면입니다.

위 사진과 같이 건물 데이터가 맵상에 올바르게 위치하였습니다.

시나리오

정보시스템은 다양한 데이터소스를 의미있게 전달하는 것으로 정의할 수 있다. 기온, 미세먼지 등 실시간으로 수치화되어 나타나는 정보는 기본적으로 데이터소스가 DB시스템에 저장된 정보가 나타나는 것이 아니라 센서에서 취득되는 정보라고 할 수 있다. 이를 사용자에게 전달하기 위한 과정은 복잡하지만 임의로 몇 개의 센서를 설치하여 센서의 정상 동작 여부를 모니터링하는 시나리오를 정의했다.

서비스바로가기

목적 및 작업 계획

  • 센서작동현황 버튼을 이용하여 사용자가 지정한 일정한 시간 간격으로 해당 데이터의 정보를 Web Socket을 이용하여 전달
  • Web Socket을 통해 전달 받은 데이터의 상태 변화를 지도 위에 시각화
  • 앞 과정을 통해 그룹 내 모든 사용자는 동일한 화면 공유 가능

구성 요약

1. Soket 서버 : 웹 브라우저와 메세지 교환

      • Web Socket의 기본형태는 아래소스와 같이 Open, Close, Error, Message 구분
      • 46행 : @onMessage를 통해 check Sensor Receiver에서 데이터 정보를 받아 데이터의 상태 정보를 전달
      • 48행 : 새로고침에 따른 중복 메세지 방지를 위해 runCheck 조건문 
      • 59행 : SensorInfo.getSensorInfo()클래스를 통해 데이터의 상태 정보 가져와 check Sensor Receiver에 다시 전달
      • 49행/70행~71행 : 타이머 기능을 통해 지정한 시간 간격으로 정보를 갱신하여 check Sensor Receiver에 전달
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package egovframework.map.service;
 
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
 
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
 
import org.springframework.stereotype.Controller;
 
import egovframework.map.web.SensorInfo;
 
@Controller
@ServerEndpoint("/websocket")
public class WSocketServer {
 
    static List<Session> sessionUsers = Collections.synchronizedList(new ArrayList<Session>());
    static Boolean runCheck = false;
 
    @OnOpen
    public void onOpen(Session userSession) {
        System.out.println("Open Connection!...");
        sessionUsers.add(userSession);
    }
 
    @OnClose
    public void onClose(Session userSession) {
        System.out.println("Close Connection!...");
        sessionUsers.remove(userSession);
    }
 
    @OnError
    public void onError(Throwable e) {
        e.printStackTrace();
    }
 
    @OnMessage
    public void onMessage(String message) throws IOException {
 
        if(runCheck == false){
 
TimerTask task = new TimerTask() {
              @Override
              public void run() {
              String sensorInfo = SensorInfo.getSensorInfo();
               Iterator<Session> itr = sessionUsers.iterator();
                  while (itr.hasNext()) {
                     try {
                         Session session = itr.next();
                        
                         session.getBasicRemote().sendText(sensorInfo);
                        
                     } catch (IOException e) {                        
                         e.printStackTrace();
                    }
                  }
 
              }
         };
        
runCheck = true;
    
         Timer timer = new Timer(true);
         timer.scheduleAtFixedRate(task, 01*1000);
    
};
    }
 
}
 

cs

2. check Sensor Receiver

check Sensor Receiver는 센서의 위치 및 상태 정보를 공유할 수 있는 페이지로 지도 위에 위치한 센서의 현재 상태 및 일정 시간 간격으로 변화 상태를 체크하여 공유할 수 있는 페이지다. check Sensor Receiver 페이지의 소스는 아래와 같다.

2.1 <script></script>부분(openlayers3 및 geojson 데이터 부분)

        • 19행 : QGIS를 통해 제작한 Json파일 경로
        • 36행 : openlayer3 map 불러오기
        • 49행 : 19행에서 지정한 경로의 파일을 geoJson 포맷으로  openlayers map에 올리기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<script type="text/javascript">
var map,
    ftData,
    vectorSource,
    vectorSocket,
    vectorLayer,
    d3Data,
    d3Style;
 
var changeFillColor,
    changeStrokeColor;
 
var raster = new ol.layer.Tile({
    source: new ol.source.XYZ({
        url: 'http://xdworld.vworld.kr:8080/2d/Base/201802/{z}/{x}/{y}.png'
    })
});
//geojson 파일 경로
var geoUrl = "/js/data/geojson/sensor_point_3857.json";
 
var ftStyle =  new ol.style.Style({
    image: new ol.style.Circle({
        radius: 10,
        fill: new ol.style.Fill({
            color: "rgba(0, 255, 0, 1)"
        }),
        stroke: new ol.style.Stroke({
            color: "rgba(0, 0, 0, 1)",
            width: 2
        }),
    })
});
 
$(document).ready(function(){
    //openlayers3 map
    map = new ol.Map({
        layers: [raster],
       
        target: 'map',
       
        view: new ol.View({
            center: [14128579.824512570.74],
            zoom: 13.5,
            maxZoom: 19
        })
    });
});
//geojson data 지도 표출
$.getJSON(geoUrl, function( data ) {
    var format = new ol.format.GeoJSON();
    
    vectorSource = new ol.source.Vector({
        features: format.readFeatures(data)
    });
    
    vectorSocket = vectorSource.getFeatures();
    
    vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style : vectorSource.forEachFeature(function(features){
            
            ftData = features;
 
            var originStyle = ftStyle;
            
            ftData.setStyle(originStyle);
        })
    });
    
    map.addLayer(vectorLayer);
    
});    
 
</script>
 
 
cs

2.2 <script></script>부분(socket 통신 부분)

        • 3행 : Web Socket통신 연결
        • 8행~11행 : Web Socket통신 function 함수 실행
        • 33행 : Web Socket통신을 통해 데이터의 정보를 전달 받아 지도 위에 표출 및 상태 메세지 전송
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<script type="text/javascript">
              
    var webSocket = new WebSocket("ws://***.***.*.**:8080/websocket2");
          
    var echoText = document.getElementById("echoText");
    echoText.value = "";
        
    webSocket.onopen = function(message){ wsOpen(message);};
    webSocket.onmessage = function(message){ wsGetMessage(message);};
    webSocket.onclose = function(message){ wsClose(message);};
    webSocket.onerror = function(message){ wsError(message);};
        
    function wsOpen(message){
        echoText.value += "Connected ... \n";
webSendMessage();
    };
    function wsCloseConnection(){
        webSocket.close();
    };
    function wsSendMessage(){
        webSocket.send(vectorSocket);
    };
    function wsGetMessage(message){
        pointStyle(message.data);
    };
    function wsClose(message){
       echoText.value += "Disconnect ... \n";
    };
 
    function wserror(message){
        echoText.value += "Error ... \n";
    };
        
    function pointStyle(ft){
        var resultStyle;
        var jsonft = JSON.parse(ft);
        var vectorFts = vectorSource.getFeatures();
            
        for(var i = 0; i < vectorFts.length; i++){
            if(i ==  jsonft.index){
                if(jsonft.code == 1){
                    //노랑
                    changeFillColor = "rgba(255, 255, 0, 1)";
                    echoText.value += i +"번 "+"센서(위치정보 :"+ vectorFts[i].getGeometry().getCoordinates()
                                +")에 이상이 감지되었습니다.(코드번호 :"+jsonft.code+"번 ) \n";
                }else if(jsonft.code == 2){
                    //빨강
                    changeFillColor = "rgba(255, 0, 0, 1)";
                    echoText.value += i +"번"+"센서(위치정보 :"+ vectorFts[i].getGeometry().getCoordinates()
                                +")센서를 점검해주십시오.(코드번호 :"+jsonft.code+"번 ) \n";
                }
                resultStyle =  new ol.style.Style({
                    image: new ol.style.Circle({
                        radius: 10,
                        fill: new ol.style.Fill({
                            color: changeFillColor
                        }),
                        stroke: new ol.style.Stroke({
                            color: "rgba(0, 0, 0, 1)",
                            width: 2
                        }),
                    })
                });
                    
            }else{
                resultStyle = ftStyle;
            }    
            vectorSource.getFeatures()[i].setStyle(resultStyle);
        };
    };        
</script>
cs

2.3 <body></body>부분

        • 5행 : openlayers map을 화면에 표출하기 위한 div태그 id 선언
        • 12행 : 데이터 작동 현황 시작 버튼 생성(Web Socket실행)
        • 49행 : Web Socket통신 종료
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="container-fluid">
    <div class="row content">
        <div class="col-sm-6" style"border-right: 1px solid;">
            <h1>Sensor Location</h1>
            <div id="map"></div>
        </div>
        <div class="col-sm-6" style"border-left: 1px solid;">
            <h1>Emergency Message</h1>
            <textarea id="echoText" rows="500" cols="700"></textarea>            
        </div>
    </div>
</div>
cs

3. 실행 화면 및 사용법

테스트는 IE, 크롬, Microsoft Edge에서 진행하였으며, check Sensor Receiver 페이지 접속 시 센서의 상태정보가 실시간으로 반영되어 센세의 상태정보가 변경된다.

  • 노란색 : 센서 상태 이상감지(코드번호 1번)
  • 빨간색 : 센서 점검 필요(코드번호 2번)

1. check Sensor Receiver 페이지를 IE, 크롬, Microsoft Edge에서 접속한다.

2. 우측 메세지창<textarea id="echoText" rows="500" cols="700"></textarea>    에 센서의 위치정보 및 이상 감지 메세지가 표출되는지 확인한다.

3.1 테스트 결과 화면

 

서비스바로가기

들어가며

 (이미지 출처: Switch from Shapefile )

작년 가을 국가지점번호를 제작하고 이를 공개하는 수단으로 Shape File (이하 SHP)을 고려했습니다. 그러나 당시 내린 결론은 "SHP는 빅 데이터(빅테이블)을 저장하거나 전달하는 수단이 될 수 없다" 입니다.  저희는 "왜 SHP를 사용하지?"라는 의문을 가지게 되었습니다.

본 글의 작성 목적은 다음과 같습니다. SHP는 우리가 사용해야 하는 데이터 형식 중 하나일 뿐이다. 하지만 현 시점에서 굳이 사용할 필요가 있을까하는 고민을 해보자는 것입니다.

SHP 파일은 무엇인가?

GIS분야에서 에서 널리 사용되는 SHP파일은 두 가지 분류가 존재합니다.  (참조: fileinfo )

  • AutoCAD shp file
    다양한 3D 디자인 프로그램에서 사용되는 객체,일반적으로 정점과 선으로 정의된 다각형을 표현
  • ESRI Shpfile
    ESRI 제품군에서 사용하는 데이터 셋으로 GIS 응용프로그램에서 점, 선, 면 같은 공간 형상요소를 저장하는데 사용

GIS사업 태동기 ESRI 제품군이 국내 GIS산업의 발전에 기여한 것은 부인할 수 없는 사실입니다. 공개SW나 대체할 수 있는 기술의 부재로 ESRI의 Arc* 제품군은 널리 사용되었습니다. 그런 이유로 SHP는 국내에서는 특히 사실 상(de facto)의 표준처럼 사용되었습니다.

 그러나 Big Data 의 출현 등 정보 이용 환경이 변함에 따라 그 한계 또한 보이고 있습니다. ESRI 또한 자신들의 사이트에서 이런 한계를 인정하고 극복하고자 노력하고 있음을 알리고 있다.

"shp 파일"은 단순 형상 지오메트리를 저장하는 데 사용할 수 있으나, 속성에 심각한 문제를 가지고 있다. 예를 들어 null 값을 저장할 수없고, 숫자를 반올림하며, 유니 코드 문자열을 제대로 지원하지 못하고, 10 자보다 긴 필드 이름을 사용할 수 없으며 날짜필드에 시간을 저장할 수 없다. 또한 도메인 및 하위 유형과 같은 지오 데이터베이스의 기능을 지원하지 않으므로,아주 단순한 속성이없고 지오 데이터베이스 기능이 필요하지 않으면 shp 파일을 사용할 필요가 없다."
(출처: ArcGIS )

SHP 문제 : 용량 제한 (Object별 2Gb)

 

다뤄야하는 데이터의 크기가 지금처럼 크지 않을 을 때 시스템간 데이터를 옮기는데 이보다 좋은 GIS 파일 형식은 존재하지 않았습니다.

 그러나 현재는 Big Data 시대입니다. 개인용 컴퓨터도 64bit이며, 사용가능한 디스크도 차고 넘치지만 SHP는 Object별(.shp, shx, dbf) 크기가 2Gb를 넘을 수 없습니다. 시대의 흐름에 맞춰 SHP가 진화를 하지 못했습니다. 


국가공간정보포털이 제공하는 연속지적도는 시도 또는 시군구로 나뉘어 배포되고 있습니다. 누군가는 구분된 것이 편하지만 그렇지 않을 경우도 있습니다.
하지만 SHP의 파일 크기 제한으로 지역별로 구분되어 배포될 수 밖에 없습니다. 
(이미지 출처: 
Switch from Shapefile )

예를 들면 Excel, Lotus123, dBaseⅢ 등은 동시대에 최고의 업무 도구였지만 지금은 파일 적재용량을 진화시켜 온 Excel만이 시장을 지키고 있습니다.  
(사실 이 부분도 시장에서 64bit 체계가 본격화 되면서 자연스레 진화 한 것이지 억지 용량을 확장 시키려 진화 한 것은 아니라고 생각된다.)

SHP는 3가지 핵심 구성요소 를 가지고 있다. *.shp, *shx, *.dbf

이 중 속성 적재 체계(*.dbf) 는 dBase의 파일적재 구조를 차용해서 사용하고 있다. 
(dBASE는 1980 년대 초에 개발 된 형식으로, 당시에는 특성 테이블을 저장하는 데 사용)

전체 3가지 구성요소 각각은 이론적으로 용량이 무제한이지만, 벡터요소를 저장하고 속성과 매칭 시켰을때 기술적 문제때문에 각각의 구성파일로 한개의 공간정보를 표출 할 수 있는 한계가 2Gb 였던 것으로 알고 있다. 
덕분에 shp 파일을 지원하는 도구들의 처리용량도 종속되어 shp 파일 용량 이상으로 확장 할 수 없다.

shp 파일은 명시적으로 32 비트 오프셋을 사용함으로 최대 8Gb 를 넘을 수 없지만 실제로는 16비트 word에 32 비트 오프셋을 사용 한다. 하지만 OGR shapefile 은 4Gb로 제한 되어 있다. 

 

SHP 문제 : 헐~ 이렇게나 많이

  • 좌표계 정의를 위한 별도 파일 요구
    좌표계를 가지기 위해 부가적으로 *.prj 파일 요구
  • 벡터, 속성, 인덱스가 분리된 다중 파일 형식
    사용자는 하나의 파일로 데이터를 주고 받을 수 없어, 네트워크 환경에서 이용하기에 제약이 존재
    (현재 zip 형식으로 배포하는 것이 가장 일반적임)
  • 속성 필드 명칭 길이 제한 (10자 보다 긴 이름을 사용할 수 없음)
  • 최대 필드 개수 제한 (DBF는 255개 이상 필드를 지원하지 않음)
  • 제한된 자료형 (Float, Integer, Date, text형의 254 character)
  • 문자 셋 이용 제한
    알 수 없는 문자 셋, 데이터베이스에서 사용되는 일부 문자셋 사용 불가, UTF-8 미지원
  • 토폴로지 (Topology)를 지원하지 않음
    지형 객체간 관계를 가질 수 없어 별도 3rd Party 도구 요구
    (Topology란 쉽게 말해서 "홍길동과 홍길순이 손을 잡았다"에서 "손을 잡았다(관계)"를 말합니다)
  • 다중 Geometry를 지원하지 않음
    하나의 SHP에 점, 선, 면을 함께 자장할 수 없습니다. 오직 한가지 형태의 도형만 저장
  • 단일 테이블만 지원
    테이블의 상속, 관계 등이 없음으로 전체 데이터 셋을 관리할 수 있는 방법을 제공하지 않음
  • Binary 형식으로 벤더 종속
    대용량 데이터의 Streaming Service 이행 불가, 기계판독(Machine-Readable)이 불가능한 벤더 종속적인 형식으로 데이터의 일부분을 가지고 시각화가 어려움

 

마치며

데이터를 개방하고 공유하는 시대입니다. SHP는 전체 시스템 관점에서 데이터를 생산하는 도구에서 사용되는 좋은 포맷일 수 있지만 개방 및 서비스를 위한 좋은 포맷은 아닙니다. 오랜기간 사용되어 친숙합니다. 편한 것 같기도 합니다. 하지만 주위를 둘러보면 이제는 다른 대안이 필요하다는 것을 알 수 있습니다.

작성하고 보니 SHP가 나쁜 놈처럼 보입니다. 그렇지 않습니다. SHP는 그 용도가 분명히 있습니다. 전체 시스템 관점에서 볼 때 언제 어떤 것이 쓰이는 것이 가장 좋을지 판단하고 사용하자라는 것입니다.

Cesium JS를 활용한 운석 낙하 시뮬레이션 

이번 시간에는 Cesium JS를 활용하여 운석 낙하 시 피해 반경을 시뮬레이션 하겠습니다.

운석 낙하는 전 세계에서 가끔 일어나는 자연현상 입니다.  과거 2013년 러시아 첼랴빈스크 지역에 운석이 낙하하여 1600여명이 부상당하고 원화 기준으로 약 350억 원의 피해가 발생 했습니다.  떨어진 운석의 크기는 직경17m, 무게 1만 톤으로 추정되었고 대기권 돌입시 추정 속도는 초속 32.5km이었습니다. 

또한 2014년 03월 경상남도 진주시에 운석이 낙하 중 폭발하였고 그 조각들이 다음날로부터 발견된 사례가 있었습니다. 

<러시아 첼랴빈스크 지역에 운석이 낙하 중인 모습과 발견된 운석의 일부 (출처-Google image검색)>

<경남 진주시에 운석 조각이 낙하중인 모습과 발견된 운석 조각 (출처-Google image검색)>

이러한 사례와 참고자료를 발판삼아 가상으로 운석이 낙하하여 충돌할 시 피해 반경을 가늠하여 보았습니다.  

샘플 프로그램 제작 당시 여의도 지역을 운석 낙하 지점으로 설정했습니다. 막상 만들고 보니 저희 나라에 운석이 떨어지는 것이 별로 좋지 않더라구요. 그래서 일본의 모 지역으로 낙하 지점을 변경했습니다. 정확한 시뮬레이션도 아니고 그저 CesiumJS를 활용하는 한 가지 사례로써 어떤 의도가 존재하지도 않습니다.

먼저 결과화면 보겠습니다.

서비스바로가기

운석은 50m급, 100m급 두 등급으로 정했습니다. 각 등급에 근접한 피해 반경을 구하기 위해 여러가지 공식과 참고자료를 활용했습니다. 하지만 참고자료 또한 추정치여서 실제와는 차이가 있습니다.
우주환경 감시기관(한국천문연구원)에서 참고한 운석의 크기와 그에 따른 충돌에너지에 대한 자료입니다.


(출처 - 우주환경 감시기관)

운석 시작 높이는 지상 100km로 설정했습니다. 대부분의 유성 및 운석이 고도 80~100km 부분 열권에서 연소가 되며 연소되지못한 운석들이 지구로 추락합니다. 

낙하속도 산출은 자유낙하 속도 공식을 활용했습니다. (v: 속도 / g: 중력가속도 / t: 시간 / s: 높이) 

 

 

시뮬레이션

시뮬레이션은 총 3단계로 진행 됩니다. 

단계1. 운석 시뮬레이션 버튼을 클릭하여 시뮬레이션 시작
단계2. 운석이 지면에 추락한 후 피해반경 표출
단계3. 피해반경 전체를 가시화

먼저 시뮬레이션 동작을 위한 버튼입니다. 50m, 100m급 시뮬레이션 버튼으로 시뮬레이션을 진행 할 수 있으며 RESET버튼으로 각 시뮬레이션을 마친 후 맵을 초기화 할 수있습니다. (하나의 시뮬레이션 진행 후 RESET기능을 통해 맵을 초기화 하세요.)

 

50m급 시뮬레이션 장면입니다. (50m급의 피해 반경은 약 11km 입니다.)

 

운석이 낙하 지점을 향해 추락하는 모습입니다.

 

 

운석이 낙하지점에 추락 후 피해반경이 표출 된 모습입니다. (50m급 운석)

 

운석 피해 반경 전체를 볼 수 있게 가시화 된 모습입니다. 100m급 시뮬레이션 장면입니다. (100m급의 피해 반경은 약 1.100km입니다.) 

 

 

프로그램 소스

시작점과 도착점을 지정하여 운석이 움직일 수 있도록 하였습니다. 이번 시뮬레이션의 기초 및 핵심이 되는 부분입니다.

 
/*  
 pos1 - 출발점 지정
 pos2 - 도착점 지정
 */
var pos1 = Cesium.Cartesian3.fromDegrees(126.50874937.369581100000.0);
var pos2 = Cesium.Cartesian3.fromDegrees(126.91362037.5192960.0);
var position = new Cesium.SampledPositionProperty();
 
position.addSample(start, pos1);
position.addSample(stop, pos2);
cs

setTimeout 콜백함수를 활용하여 시간에따른 시뮬레이션을 진행하는 부분입니다.

 
// 운석이 도착점에 도달할 시 피해반경 표출
setTimeout(function(){
    viewer.entities.add({
        position : meteorPosition,
        ellipse : {
            semiMinorAxis : 11000.0
            semiMajorAxis : 11000.0
            material : Cesium.Color.RED.withAlpha(0.5)
        }
    });
},23000); 
// 피해반경 가시화 
setTimeout(function(){
    if(particleSystem != null){
        scene.primitives.remove(particleSystem);
    };
    var staticPosition = Cesium.Cartesian3.fromDegrees(139.74390335.69436360000);
    var orientation = new Cesium.HeadingPitchRange(0,300,0); 
    viewer.scene.camera.setView({
        destination : staticPosition,
        orientation : orientation,
        endTransform : Cesium.Matrix4.IDENTITY
    });
},26000);
cs

semiMinorAxis 와 semiMajorAxis는 지름을 지정하는 파라미터입니다. 단위는 m입니다.

 

마치며

본 시뮬레이션을 구현하는 작업은 흥미로웠습니다. 하지만 운석낙하에 대한 자료가 한참 부족하고 대부분 추정치만 존재하다보니 실제의 값에 근접한 값을 도출하는데 수 일의 노력을 기울였습니다.

하지만 프로그웍스와 독자분들을 위한 유령개구리의 노력은 멈추지 않을것입니다. 감사합니다~!

 

 

 

 

 

 

 

시나리오

좋은 서비스를 위하여 데이터의 품질을 높이는 것은 무엇보다 중요합니다. 품질을 높이는 가장 좋은 방법은 육안으로 점검하여 오류를 수정하는 것이지만 이는 많은 비용을 요구합니다. 

1. 간단하게 할 수 있는 방법으로 PostGIS를 이용하여 도형의 무결성을 검증하고, 오류가 있는 도형을 수정하도록 합니다.
2. SQL 을 통해 도형형상을 수정하고 QGIS에서 이를 검증합니다.

 

수행 절차

1. ST_IsValid 함수를 이용하여 유효하지 않은 지형객체 추출 (울주군 추출)

with testdata as
(select ufid, bjcd, name, ST_IsValid(geom) as validflag, geom  from sigungu_5179)
select ufid, bjcd, name, geom from testdata where validflag = 'f';

2. ST_MakeValid 함수를 이용하여 유효한 도형으로 수정

create table sgg_tmp_5179_31710 as
select ufid, bjcd, name, ST_MakeValid(geom) as geom  from sigungu_5179  where bjcd = '3171000000';

3. ST_IsValid 함수를 이용하여 수정된 도형의 무결성 검증 (TRUE: 유효한 도형임)

select ST_IsValid(geom) from sgg_tmp_5179_31710;
 

맺음말

이 전 게시글에 비하면 쉬운 주제입니다. 그러나 이 전 주제에 비하여 무엇보다 중요한 일입니다.

일반적으로 원시 데이터가 품질 문제를 가지고 있는 경우도 있지만, 서비스 이행을 위하여 단순화(Simplify) 과정을 거치게 되면 거의 대부분 무결성 오류가 발생합니다. 따라서 단순화를 진행했다면 꼭 무결성을 검증하여 발생한 오류를 수정해야 합니다. 귀찮더라도 데이터를 이용하는 사용자의 편의를 위하여 데이터의 무결성 오류를 제거하는 습관을 가져야 합니다.

수치지형도 등고선(SHP)을 이용하여 DEM 이미지 제작 과정

> 관련 글 바로가기 : 국가공간정보포털 DEM자료 활용하기

 

시나리오

국가공간정보포털 오픈마켓이 개방하는 DEM 이미지를 이용하여 3D 지형모델을 이전 글에서 작성했습니다. 그러나 배포하는 영상의 해상도가 90m급으로 제약이 있어 정교한 지형 모델을 만들기에는 애로가 있었습니다. 이에 DEM 파일을 찾고자 노력했지만 역시나 찾기 어려웠습니다. 저희는 언제나처럼 저희가 직접 해결하기로 결정하고, 방법을 생각했습니다.

수치지형도2.0의 등고선 레이어는 상당히 정교합니다. 저희는 이를 다운로드 받아 PostGIS에 적재하여 지점 별 높이 정보가 들어있는 벡터 데이터 셋을 제작합니다. 그 후 QGIS가 제공하는 RasterCreationTool을 이용해 DEM을 제작합니다.
제작과정에서 수치지형도를 다운받아 PostGIS에 적재하는 과정은 생략합니다. 각 과정의 결과물은 QGIS를 통해 확인합니다.

 

DEM 제작 과정 

1. 등고성 테이블의 단순화 (선택적 작업 : 작업PC의 성능 문제로 경량화 진행)

PostGIS가 제공하는 단순화 함수에는 ST_Simplfy 와 ST_SimplifyPreserveTopology가 있습니다. 후자를 이용하는 것이 좋습니다. 함수의 상세한 설명은 PostGIS 공식 매뉴얼을 참조하십시오. 요즘 Geo Processing을 진행하며 PC 성능의 한계를 느끼고 있습니다. 아직은 PC보다 제 생각이 빠르다는 것에 약간의 만족감을 가지며 위로합니다.

CREATE TABLE tmp_contour_sim_5179 as
    select cont, ST_SimplifyPreserveTopology(geom, 5) as geom from tmp_contour_5179;

2. 단순화된 등고선 Polygon의 Point 전환 (이후 시군구 추출을 위해 공간인덱스 생성)

ST_Dumppoints 함수를 이용하여 등고선 다각형을 구성하는 개별 점을 추출하고, 추출된 각 점에 다각형이 가지던 높이 정보를 그대로 넣어줍니다. 

CREATE TABLE tmp_alt_5179 AS
    select pts.alt as alt, (pts.geoms).geom as geom from
    (select ST_dumppoints(geom) as geoms, cont as alt from tmp_contour_sim_5179) as pts;

CREATE INDEX tmpalt_geom_idx ON public.tmp_alt_5179 USING gist(geom);  

3. 양양군 지역의 높이 추출

ST_Intersects 를 이용하여 양양군 지역 만을 추출합니다. 양양군의 경계를 그대로 이용할 수 있지만 ST_Envelope 함수를 통해 사각형 형식으로 추출했습니다. 향후 개별 시군구를 통합한 DEM을 제작하는 경우 래스터 영상은 영상 정합을 통해 겹치는 지역의 처리를 어렵지 않게 할 수 있습니다. "With"를 이용하는 이유는 성능입니다. 실행도 중요하지만 실행하는 속도 또한 프로그램으로 이행한다면 중요한 요소입니다.

create table tmp_alt_5179_42830 as
    with bound as (select ST_envelope(geom) as geom2 from sigungu_5179 where bjcd = '4283000000')
    select dem.alt, dem.geom from (select alt, geom from tmp_alt_5179) dem, bound
        where st_intersects (dem.geom, bound.geom2) = true;

4. QGIS 의 SAGA > Raster Creation > Natural Neighbor 를 이용한 DEM 이미지 제작

QGIS는 강력한 도구입니다. 우리가 흔히 다루는 벡터 형식(SHP 등) 말고도 Raster를 위한 강력한 도구를 제공합니다. QGIS의 "공간처리툴박스"는 다양한 공개SW 및 라이브러리를 쉽게 쓰도로 지원합니다. 저는 많은 도구 중 "SAGA"를 이용했습니다. "SAGA"에는 많은 도구가 존재하며 저는 그 중에서 "Raster Creation Tools"의 "Natural Neighbor"를 이용했습니다.

마치며

항상 대안은 존재합니다. 국가공간정보포털이 제공하는 90m급 DEM 이미지보다 정교한 50M급 DEM 이미지를 제작했습니다. 아래 그림을 통해 90m급 DEM 과 저희가 제작한 50m 급 DEM의 정교함을 비교할 수 있습니다. 


<50m 급 DEM>


<오픈마켓 배포 90m 급 DEM>


<50m 급 DEM 패턴 매칭>


<90m급 DEM 패턴 매칭>

What's ELK, Filebeat?

 

 

 

  • Elasticsearch: Apache Lucene을 기반으로 개발한 실시간 분산형 RESTful 검색 및 분석 엔진
  • Logstash: 각종 로그를 가져와서 JSON 형태로 만들어 Elasticsearch로 데이터를 전송함
  • Kibana: Elasticsearch에 저장된 데이터를 사용자에게 Dashboard 형태로 보여주는 시각화 솔루션
  • Filebeat: 로그 파일을 경령화시켜서 Elasticsearch 또는 Logstash로 넘겨주는 역할을 수행함. 특히, Logstash가 과부하되면 넘기는 속도를 줄여주고, 시스템 가동이 중단되거나 다시 시작해도, 로그의 중단점을 기억하고 그 지점부터 다시 보낼 수 있음

프로그웍스가 ELK에 관심을 가지계 된 계기는 다음과 같습니다. 클라우드 환경에서 마이크로아키텍처에서 탑재되는 개별 모듈의 동작상태를 관제하기 위한 방법이 무엇이 있을까 고민하던 중 한가지 방법이 될 수있겠다라고 생각했습니다.

1. 제작되는 개별 앱 또는 모듈의 로그작성 규칙을 통일하고 
2. filebeat를 통해 로그파일에서 원하는 것을 수집하여
3. 대쉬보드에 출력한다면,

VM, 컨테이너, 물리머신 등 환경에 상관없이 운영정보를 관리할 수 있을 것이다. 우선은 여기까지만 생각합니다. 이 후 발전시켜 나가겠습니다.

How to install the ELK, Filebeat?

 

우선 JDK를 설치한다(JDK를 설치하지 않았을 경우 진행). 

$sudo yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel 

 

그리고, 아래 환경변수를 /etc/profile 에 추가하고 적용한다.

$sudo vi /etc/profile  # 아래 내용 추가 export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.102-1.b14.el7_2.x86_64 export PATH=$PATH:$JAVA_HOME/bin export CLASSPATH=.:$JAVA_HOME/jre/lib:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar  # 환경변수 등록 $source /etc/profile

 

 

1. Elasticsearch

/etc/yum.repos.d/에 elasticsearch.repo 내용을 추가한다.

[elasticsearch-6.x] name=Elasticsearch repository for 6.x packages baseurl=https://artifacts.elastic.co/packages/6.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md 

 

 이제 yum 으로 설치한다. 

$sudo yum -y install elasticsearch 

 

2. Logstash

위의 Elasticsearch 설치 과정과 동일하다.

$sudo vi /etc/yum.repos.d/logstash.repo  # 아래 내용 추가 [logstash-6.x] name=Elastic repository for 6.x packages baseurl=https://artifacts.elastic.co/packages/6.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md  # 설치 $sudo yum -y install logstash

 

 

3. Kibana

위의 Elasticsearch 설치 과정과 동일하다.

$sudo vi /etc/yum.repos.d/kibana.repo  # 아래 내용 추가 [kibana-6.x] name=Kibana repository for 6.x packages baseurl=https://artifacts.elastic.co/packages/6.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md  # 설치 $sudo yum -y install kibana 

 

Kibana를 설치했으면 Host(호스트), Name(이름), SSL(해도 되고 안 해도 됨)을 설정한다. SSL 설정을 했을 경우 SSL 인증서의 권한도 같이 수정해야 한다. 만약에 시스템에서 방화벽을 사용하면 포트 설정도 추가한다.

$sudo vi /etc/kibana/kibana.yml

 

 # 서버 호스트 및 이름 입력(여기서는 elk.com 사용)  server.host: "127.0.0.1"  server.name: "elk.com"

 

 # 로그가 담긴 Elasticsearch 주소 입력  elasticsearch.url: "http://127.0.0.1:9200"  # SSL 설정 # 서버를 내부에서만 사용하면 할 필요는 없다. 하지만, 외부에서 연결하여 사용할 경우 

# 보안성을 위해 SSL 설정을 반드시 해야 한다. server.ssl.enabled: true # .crt 파일 경로 입력 server.ssl.certificate: # .key 파일 경로 입력 server.ssl.key: # SSL 인증서 권한 수정 $sudo chown kibana. 경로(.crt와 .key 파일 둘 다 설정해야 함) # 필요시 방화벽 설정 $sudo firewall-cmd --add-port=5601/tcp --permanent $sudo firewall-cmd --reload

 

4. Filebeat

위의 Elasticsearch 설치 과정과 동일하다.

$sudo /etc/yum.repos.d/elastic.repo  # 아래 내용 추가 [elastic-6.x] name=Elastic repository for 6.x packages baseurl=https://artifacts.elastic.co/packages/6.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md  # 설치 $sudo yum install -y filebeat

설치가 완료되면 Filebeat에서 보낼 로그의 경로를 설정한다. 여기서는 Logstash를 사용하므로, output 쪽에 logstash로 지정한다.

$sudo vi /etc/filebeat/filebeat.yml  # 아래 내용 추가 filebeat.prospector: - input_type: log   paths:     # 쉘 명령어들을 기록한 로그     - /var/log/bash_history     # MySQL 로그     - /var/log/mysql/*     # Apache httpd 로그     - /var/log/httpd/*

 

output.logstash:   hosts: ["127.0.0.1:5044"] 

 

그리고, Filebeat로 보내진 로그를 Elasticsearch로 보내는 설정을 한다. 참고로 Filebeat 외 다른 beat(Metricbeat, Packetbeat, Heartbeat, Winlogbeat 등)에서 보낸 로그를 포함하여 이를 모두 Logstash에서 직접 로그를 보낼 수 있다.

$sudo vi /etc/logstash/conf.d/filebeat.conf  # 아래 내용 추가 input {   beats {     port => 5044     host => "0.0.0.0"   } } output {   elasticsearch {     hosts => ["http://127.0.0.1:9200"]     index => "%{[@metadata][beat]}-%{+YYYY.MM.dd}"      document_type => "%{[@metadata][type]}"   } } 

 이제 Kibana에서 위에서 설정한 로그를 확인할 수 있다.

# 서비스 모두 재시작  systemctl restart elasticsearch  systemctl restart logstash  systemctl restart kibana  systemctl restart filebeat 

 혹시 서비스 시작 도중 시스템이 느려지면 RAM 4GB 이상 설정한다. 이제 http://127.0.0.1:5601에 접속하면 Kibana가 정상적으로 실행된다. 처음에 Index Pattern이 없다고 나온다. 그러면 curl localhost:9200/_cat/indices?v 명령어를 실행해서 Elasticsearch에 저장된 Index Pattern을 확인하고 Kibana에 추가하면 된다 (여기서는 filebeat-로 추가했다. Index Pattern은 추후 원하는 대로 수정 가능하므로 참고할 것*). 이제 Dashboard 혹은 Discover 메뉴에서 보고 싶은 로그를 필터링하여 볼 수 있다.

 

[curl localhost:9200/_cat/indices?v 실행 결과]

 

[Index Pattern 설정]

 

[SQL Injection 공격 시도 MySQL 로그]

 

[사용자가 su 명령어를 입력한 로그를 추출한 결과(원하는 Command List를 입력해서 로그를 확인 가능)]

 

마지막으로, SQL Injection 공격 시도가 있을 때 ssl_error_log에서 아래처럼 POST Body 메시지를 볼 수 있다. Logstash 덕분에 JSON 형식으로 잘 넘어온다.

 

 

 

DEM 이란?

DEM(Digital Eleveation Model) 실세계 지형 정보 중 건물, 수목, 인공 구조물 등을 제외한 지형 부분을 표현한 모형

DSM(Digital Surface Model) 실세계의 모든 정보, 즉 지형, 수목, 건물, 인공구조물 등을 표현한 모형 (네이버 지식백과)

 

 

국가공간정보포털에서 제공하는 수치표고모델(DEM)를 Qgis에서 활용해보겠습니다. (Qgis version 3.4.4)

수치표고모델(DEM) 다운로드

해당 자료를 다운로드 후 압축해제하면 3종류의 폴더가 존재하는데  ascil(공백으로 구분되어 있는 x, y, z 값 텍스트 파일), img, pdf 파일이 있습니다.

Qgis에 드레그 드랍으로 img 파일을 추가

 

1. 해당 자료를 확대하여 확인해보면 90m 간격으로 픽셀이 연결되어 있으며 픽셀에 하나의 고도값을 가지는 것을 확인 할 수 있습니다.

 

2. 자료를 추가하신 뒤에 Qgis 상단 메뉴에 '보기 > 새 3D 맵 뷰' 버튼을 클릭하면 해당 DEM자료가 3D 뷰어로 표출됩니다.

3D뷰어에서 환경설정 버튼을 선택하시면 위의 3D Configuration 창이 활성화 되고 사용하려는 값을 지정해 주시면 됩니다.

  • 고도 : 해당 수치지형도
  • 수직축척 : 2
  • 나머지 설정값을 Default로 하여 확인버튼

 

해당 픽셀의 고도값에 따라 지형이 변형된 것을 확인할 수 있습니다.

 

3. Tile 이미지를 DEM 자료위에 중첩시켜 좀더 시각적 효과 주기

Qgis 왼쪽 탐색기 패널에 'XYZ Tiles' 카테고리에서 마우스 오른쪽 버튼을 클릭하여 New Connection을 클릭합니다.

명칭과 URL을 입력하고 확인 버튼을 클릭합니다.

이후 사용하고 싶은 Tile을  레이어 추가하여 DEM자료에 중첩시킵니다.

저는 구글 위성지도를 사용하였습니다. 이외에도 구글에서 제공하는 타일서비스는 아래와 같습니다.

>Roadmap
http://mt0.google.com/vt/lyrs=m&hl=en&x={x}&y={y}&z={z} 

>Terrain
http://mt0.google.com/vt/lyrs=p&hl=en&x={x}&y={y}&z={z}

Altered roadmap
http://mt0.google.com/vt/lyrs=r&hl=en&x={x}&y={y}&z={z}

>Satellite only
http://mt0.google.com/vt/lyrs=s&hl=en&x={x}&y={y}&z={z}

>Terrain only
http://mt0.google.com/vt/lyrs=t&hl=en&x={x}&y={y}&z={z}

>Hybrid
http://mt0.google.com/vt/lyrs=y&hl=en&x={x}&y={y}&z={z}

>Vworld Satellite
http://xdworld.vworld.kr:8080/2d/Satellite/201710/{z}/{x}/{y}.jpeg

 

4. 포인트를 DEM 자료 변경

위에 언급되어 있듯이 'ascil' 폴더에 공백으로 구분되어 있는 x, y, z 값 텍스트 파일을 이용하여 좀더 조밀한 DEM자료로 변환해보겠습니다.

레이어 > 레이어추가 > 구분자로 분리된 텍스트 레이어를 추가

 

공간 처리 툴박스를에 SAGA > Raster creation tools > Natural neighbour 

 

 

Cellsize : 50m로 지정하여 기존격자(90m)보다 조금더 조밀하게 설정하겠습니다.

이제 해당 자료를 다시 위와 같은 방법으로 3D뷰어에 타일이미지를 이용해 시각적효과를 주겠습니다.

 

5. 임의로 90m급 DEM자료를 더 조밀한 간격으로 변경했을때의 문제점

기존 90m셀이 50m로 변경되면서 보정법에 의해 어느정도 수치가 맞추어 지는데, 50m 와 100m 사이에 보정한 셀의 고도값이 75m로 임의값이 정해지지만 실제로 90m셀 두개의 간격 사이에 수많은 고도 값이 존재할 것이기 때문에 75m는 정확한 값은 아닙니다.

* 90m급 DEM자료는 90m급에서 사용하자

남북 대치 상황에서 보안 관련 사항은 무엇보다 중요합니다.

저희는 공개SW를 이용한 GIS 활용을 돕고자하는 순수한 뜻으로 글을 작성하고, 예제를 제공합니다. 하지만 본의 아니게 저희의 예제가 군사 시설 등을 그대로 노출하고 있어 일부 서비스에 대한 변경을 가져갈 수 밖에 없음을 알려드립니다.

저희가 제공하는 예제의 일부는 배경지도로써 "OpenStreetMap"(이하 OSM) 을 이용합니다.  OSM은 전세계 사용자의 참여에 의해 만들어지는 지도이다보니 남북이 대치하는 국내 실정을 반영하지 않습니다. OSM에는 군사시설 등의 위치가 그대로 노출되는 문제가 있습니다.

금일 모기관에서 OSM을 사용하지말 것을 권고 받았습니다. 속상하지만 국가 정책은 당연히 따라야 한다고 생각합니다. 그래서 어쩔 수 없이 저희가 게시하는 국가지점번호지도서비스의 배경도를 Vworld로 변경합니다.  국가가 공공개방하는 정보와 인터넷을 통해 널리 활용되는 것의 사용에도 제약이 존재하네요.

Vworld 2D Map의 경우지원하는 축적범위가 최대 확대 수준을 기준으로 OSM 대비 2단계 낮습니다. 이에 앞으로 저희가 공개하고 있는 "국가지점번호 지도서비스"에서 "10m X 10m"격자가 가리키는 지형사물을 식별 할 수 없습니다. 양해 부탁드립니다.

아래 그림은 OSM과 Vworld Map 의 동일지역의 Portrayal 차이입니다.

 

> 바로가기 : 국가지점번호 지도서비스 게시글
> 바로가기 : 국가지점번호 지도서비스

+ Recent posts