Vworld의 3d data api에서는 여러가지 3차원 정보들을 받아올 수 있다. 여기서는 건물과 교량 모델링 데이터를 받아오는 법을 다룬다. 자바(JAVA) 언어를 다룰 수 있어야 쓸 수 있다.


Vworld.kr 에 접속하면 전국 곳곳의 지형과 건물들을 3차원으로 볼 수 있다. 이 데이터들은 3d data api를 통해서 제공하며, 일괄적으로 다운로드 받는 방법은 없다. 따라서 우선 이용하려면 api key를 신청해서 받아야 하고, building 3d data 에서 제공하는 xdo 바이너리 파일을 받아서 파싱한 후 3d 프로그램에서 쓸 수 있도록 재구성해야 한다. 아마도 그래픽스 전공자들에게는 어려운 일이 아닐 것 같지만, 일반 사용자들이 그 방법을 습득하고 재구성하기는 쉽지 않다. 


여기에서는 영역의 좌표점들을 보냈을 때 건물 데이터와 최상위 텍스쳐 데이터를 받아서 3d프로그램에서 읽어들일 수 있는 범용 파일 형식 중 하나인 .obj 으로 저장한다. 불필요한 트래픽을 막기 위해 한번 받았던 영역과 겹치는 부분들은 중복다운받지 않고 기존 파일에서 추출하여 저장할 수 있도록 했다.


3차원 건물 구축지역은 많지 않다. 서울의 경우 아쉽게도 5년~9년 전이 최신 데이터다. 데이터를 이용하는 사용자 층이 두터워지고 활용도가 높아지면, 담당 부서에서도 지속적으로 데이터 구축을 추진해 줄것이라 기대하면서 아래의 코드를 공개한다. 단, 불필요한 영역을 과도하게 끌어와 서버의 부하를 증가시킬 경우 이 서비스를 지속적으로 이용하고 싶은 타인에게 의도치 않게 피해를 줄 수 있음을 한 번쯤 생각해보자.


아래는 구축된 영역을 나열해놓은 것. 추가적인 지역은 여기서 확인할 수 있다. '3차원도고해상도구축지역' FAQ를 조회하면 된다.





기본 소개


OPEN api를 이용하려면 우선 브이월드에서 회원가입을 하고 api 키를 발급받아야 한다. 찾아보면 어렵지 않으니 하나 받아두어야 아래에서 소개하는 코드에 집어넣어 동작시킬 수 있다. 신청할 때, '서비스할 웹주소'를 적게 되어 있는데, http://localhost:4141 으로 적어서 신청하면 추가적인 코드 수정 없이 사용할 수 있다. building3dCrawler.java 파일을 찾아보면 앞 부분에 api키와 서비스웹주소를 적어넣어야 하는 부분이 있다.



브이월드 개발자센터의 <3D 데이터API레퍼런스>를 읽어보면, 사실 설명이 pdf문서로까지 자세히 써 있는데, 읽어봐도 이해하기 쉽지 않다. 바이너리 파일을 직접 다루어야 하고, 레퍼런스에서 가르쳐주지 않는 좌표변환방법을 찾아내야 하며, 3차원 모델로 만들려면 좌표들을 재조합해서 건물로 만들 수 있어야 한다.


그래서 아래에서는 그 과정들을 코드가 알아서 처리하도록 해 두었으며, 사용하는 사람은 다음의 내용들만 입력하면 된다. building3dCrawler.java 의 36~67번 라인에 해당 부분이 있다.


1. 데이터를 받으면 지속적으로 저장할 폴더. 한번 설정하면 바꾸지 않는다.

2. 현재 구성해보고자 하는 특정 영역만 저장할 폴더. 매번 바꾸는 것을 권장한다.

3. api키와 referer(서비스할 웹주소. 자신의 컴퓨터에서 작업한다면, localhost로 둔다. 위의 문단 참고)

4. 받아오고자 하는 영역의 좌하단, 우상단 경위도 좌표

5. 건물을 받아올 경우와 교량을 받아올 경우 선택


1번과 2번의 폴더를 구분하는 이유는, 한번 받아온 같은 해상도의 같은 영역은 다시 받지 않기 위함이다. 그래도 특정 사각 영역을 받아오고자 할 때 해당 영역들은 한 폴더에 모여 있어야 다루기 수월하므로 2번 폴더를 별도로 두었다.

물론 자바 언어를 실행시킬 수 있어야 원하는 내용을 얻을 수 있다. 그리고 계산 자체는 그렇게 복잡하지 않기 때문에 다른 언어 사용자들이 해당 언어로 바꾸는 작업이 어려울 것이라 생각하지는 않는다. 모든 필요와 요구에 대해서 상세히 설명하지 못하는 부분을 이해해 주셨으면 한다.





코드 작동 순서


1. 

일단 영역의 경계점 좌표를 입력하면 브이월드에서 다루는 Idx,Idy 영역번호로 변환한다. 원래 브이월드에서 소개하는 절차에서는 query를 보낸 후 받아와야 하지만 계산이 어렵지 않으므로 직접 계산하였다. 두 단계를 생략하여 request를 최소화한다.


2. 

idx,idy의 list를 산출해 낸 뒤 request를 보내서 .dat 파일들을 받아온다. 바이너리 파일이며, 해당 단위 구간 안의 건물들 데이터 목록(xdo형식)이 들어있다. 받아오기 전에 저장 폴더의 목록과 대조하여 이미 존재하는 파일은 다시 받지 않는다. 이하 마찬가지다.


3.

dat 파일을 파싱하여 xdo파일들 목록을 얻고, 다시 요청하여 xdo파일들을 받아온다. 하나의 dat파일에 0개~십수개의 xdo파일들이 있다.


4.

xdo 파일들을 읽어낸다. 여기에는 obj 형식으로 건물 데이터를 재조합할 때 필요한 정보들이 있다. vertex 좌표값, vertex normal, 텍스쳐 매핑에 필요한 vertex UV, face 구성 순서, 텍스쳐 이미지 이름과 최하위 해상도 텍스쳐가 들어 있다.


5. 

xdo 파일에 있는 텍스쳐 이름을 꺼낸 후 최상위 해상도의 텍스쳐 파일을 요청하여 얻어온다.


6.

obj파일을 만든다. 한 세트의 idx idy 구역안에 있는 건물들은 하나의 obj파일로 만든다. 그룹(g)으로 구분한다.

건물에 텍스쳐를 입히려면 obj, mtl, jpg들의 세가지 형식이 조합되어야 한다.

obj에는 좌표값 등 물리적인 정보와, 각 그룹(건물)마다 어떤 material 정보를 사용할 것인지를 명시해준다.

mtl은 obj에서 부여했던 material 정보그룹의 고유번호들을 매개로 diffuse 색, 투명도, 텍스쳐 이미지 등 여러가지를 지정해줄 수 있다. mtl에서 지정한 jpg들까지 한 폴더 안에 있어야 텍스쳐들이 건물에 입혀진다. 그래서 위에서 구분한 데이터 저장 폴더에 기본적으로 jpg들을 저장하고, 영역을 설정한 부분이 저장되는 target folder에 그때그때 복사해 오도록 했다.

건물에 텍스쳐를 입히고 싶지 않다면, jpg들을 obj 폴더에서 제거해주면 된다.


7.

obj 파일은 두 가지 좌표계로 저장된다.

*. 둥근 지구 그대로의 3차원 좌표

*. 평평한 지구를 가정한 상태에서 UTMK(EPSG:5179) 좌표계에 건물들을 각각의 해발고도에 위치시킨다. 대부분 이 방식이 편리할 것 같다.



코드 내용


https://github.com/vuski/getVworld3D

이 곳에서 볼 수 있다.


https://github.com/vuski/getVworld3D/blob/master/src/vworld/Building3dCrawler.java

여기에 핵심적인 내용들이 있다.

주석을 되도록 많이 달아놓아서 다른 언어 사용자들이 포팅하는데 도움이 되도록 했다.



부가 설명


*.

이 코드를 통해서 건물 혹은 교량을 받아올 수 있다.

건물을 받을 경우 그대로 사용하면 되고, 교량을 받을 경우 아래 부분의 주석 처리를 서로 바꿔줘서 변수 값이 대체될 수 있도록 한다.


//교량은 레벨 14에서 받아와야 한다.

//static String layerName = "facility_bridge";

//static int level = 14;

//건물은 레벨 15에서 받아와야 한다.

static String layerName = "facility_build";


static int level = 15;


*. 

위경도와 UTMK 좌표 변환은 proj4j 라이브러리를 사용했다. 여러가지 좌표계 상호 변환을 할 수 있는 유명하고 강력한 라이브러리다. lib 폴더에 넣어놓았다. 다음의 경로에 설명이 있다.

https://trac.osgeo.org/proj4j/


지속적으로 변환설정값을 호출할 경우 많이 느려지기 때문에 static으로 두어 앞으로 꺼냈다.

csName2를 바꿔주면 다른 좌표계로도 바꿀 수 있다.


static String csName1 = "EPSG:4326";

static String csName2 = "EPSG:5179";

static CoordinateTransformFactory ctFactory = new CoordinateTransformFactory();

static CRSFactory csFactory = new CRSFactory();

static CoordinateReferenceSystem crs1 = csFactory.createFromName(csName1);

static CoordinateReferenceSystem crs2 = csFactory.createFromName(csName2);

static CoordinateTransform trans = ctFactory.createTransform(crs1, crs2);

static ProjCoordinate p1 = new ProjCoordinate();

static ProjCoordinate p2 = new ProjCoordinate();


*.

기본적으로 다운 받는 좌표들은 둥근 지구를 가정하여 건물이 이리저리회전되어 있다. vworld.kr에서 바로 볼 수 있는 3차원 지도 역시 둥근 지구 위에 올라가 있다. 

이 코드에서는 둥근 지구와 동시에 해당 파일들을 다시 평평한 평지 위로 되돌려서 저장한다.

혹시나 브이월드에서 좌표 변환을 시도했는데 잘 안되었던 사람들이 있다면 아래 부분이 핵심이므로 참고하면 된다.


float[] xyz = rotate3d(vx, vy, vz, lon, lat);


vertex[i][0] = p2.x + xyz[0];

vertex[i][1] = p2.y -1 * (xyz[1]);
vertex[i][2] = xyz[2] +objxyz[2] -6378137;
vertex[i][3] = vnx;
vertex[i][4] = vny;
vertex[i][5] = vnz;
vertex[i][6] = vtu;

vertex[i][7] = (1.0f-vtv);


rotate3d 메서드는 아래와 같이 구현하였다.


private static float[] rotate3d(float vx, float vy, float vz, double lon, double lat) {

float x,y,z;

double p = (lon)/180 * Math.PI;

double t = (90-lat)/180 * Math.PI;


 //원래 회전공식대로 하니까 90도 회전된 결과가 나와 z축을 중심으로 다시 -90도 회전을 했다.

y = (float) (Math.cos(t)*Math.cos(p)*vx - Math.cos(t)* Math.sin(p) * vy - Math.sin(t)*vz);

x = -1 *(float) (Math.sin(p)*vx + Math.cos(p)*vy);

z = (float) (Math.sin(t)*Math.cos(p)*vx -Math.sin(t)*Math.sin(p)*vy + Math.cos(t)*vz);

return new float[]{x,y,z};

}


*. 

모델링의 기본 material 속성은 아래와 같이 두었다.

값들을 추가하거나 원하는 대로 변경할 수 있다. 아래에서 설명하는 mtl파일 상세 페이지를 참고하면 된다.


Ka 0.000000 0.000000 0.000000

Kd 1.000000 1.000000 1.000000

Ks 1.000000 1.000000 1.000000

Tf 0.0000 0.0000 0.0000

d 1.0000

Ns 0



*. 

obj 파일에 대한 개략적인 정보는 아래를 참고한다.

https://en.wikipedia.org/wiki/Wavefront_.obj_file#Vertex_texture_coordinate_indices


obj 파일에 대한 상세한 정보는 아래를 참고한다.

http://paulbourke.net/dataformats/obj


mtl 파일에 대한 상세한 정보는 아래를 참고한다.

http://paulbourke.net/dataformats/mtl/


*.

라이노에서 obj 파일을 import 했을 때, 화면에 아무것도 안 보이는 것이 당연하다. x와 y좌표가 UTMK 좌표값이기 때문이다. Zoom Extents All 해야 화면 안으로 들어온다. 각자의 고유 좌표를 유지하고 있어야, 여러가지 지리 정보를 조합해도 어긋남 없이 잘 들어맞기 때문에, 원점이 아니라 다소 불편하더라도 이동하지 말고 그대로 사용할 것을 권장한다.



*.

다른 언어로 포팅할 경우, 깃헙 등에서 연결시켜 공개해 주셨으면 좋겠다.



COMMENT : 0 TRACKBACK : 0

Category

Etc.

Date

2018.03.24 16:50

위로가기