지도 엔진의 라벨 회전 기능

오늘 또 김연아의 무결점 환상 연기.. 단 한차례의 NG도 없는.. 역대 최고의 점수를 획득했습니다. 정말 자랑스럽습니다..!

GIS 데이터를 그래픽 요소와 문자 요소를 기준으로 살펴보면 도형 데이터와 속성 데이터로 구분됩니다. 이때 도형에 대한 속성을 화면상에 표시하는 것을 라벨(Label) 또는 주기(Annotation)이라고 하는데.. 이 라벨을 표현하는 방법 또한 다양합니다. 단순히 속성 값을 표시하는 것에서 부터.. 다수의 속성을 표현식으로 조합하여 표현하는 방식과 멀티 라인 속성 방식.. 그리고 폴리라인을 따라 회전하는 표현 방식이 있습니다.

사용자 삽입 이미지
위의 이미지는 Xr 맵엔진에서 각 도형에 해당되는 속성을 도형에 따라 회전하며 라벨 텍스트를 표현하는 방식입니다. 이런 표현 방식은 위의 이미지처럼 도로명을 표현할때 매우 효과적인 방식입니다. Xr 맵 엔진은 지도 타일 이미지를 전문적으로 렌더링하기 위한 1차 목표를 추구하기 위한 맵 엔진입니다. 최근 RIA를 기반으로 한 지도 엔진 개발을 최종 목표로 하고 있는 프로젝트에서 Xr 맵 엔진은 첫 관문으로써 매우 중요한 의미를 가지고 있습니다.

Mobile 3D Graphics, 역자 서문 작성 완료..!

사용자 삽입 이미지9월말에 번역 끝내고 출판사에 보냈더랬습니다. 대략 1달정도 교정되어 인쇄된 교정지를 받아보고 참으로 감동스러웠더랬는데… 다시 교정하시는 분이 지적한 부분을 보완해서 보내고.. 다시 2주 정도 기다린 지금.. 역자 서문을 요청 받아 그것까지 보냈습니다. 아마 11월 말쯤 출판이 된다고 하니.. 실제로 출판된 책을 보면 또 어떤 기분일지 궁금합니다..

아래는 오늘 작성해서 보낸 역자 서문입니다. 이 서문은 교정을 보지 않아서 어색한 부분이 많습니다. 이해해 주시고 살펴보시면 감사하겠습니다..

역자 서문


현대의 컴퓨팅 환경은 웹을 뛰어 넘어 언제 어디서나 원하는 정보를 쉽게 접근할 수 있는 모바일 디바이스를 이용한 모바일 플랫폼이 대세를 이루고 있다.


개발자에게 모바일 플랫폼에서의 개발 환경은 마이크로소프트의 Windows Mobile, 구글의 안드로이드, 애플의 iPhone 등이 있습니다. 이들 모두가 서로 상이한 개발 API를 제공함으로써 개발자를 혼란스럽게 하지만 3차원 그래픽 개발에 있어서는 OpenGL ES나 M3G라는 공개된 표준 API를 제공하여 개발 방법을 단일화 해주고 있습니다.


C/C++과 같은 네이티브 언어에서의 OpenGL ES와 Java에서의 M3G라는 표준 API를 사용함으로써 거의 대부분의 모바일 플랫폼에서 개발자가 원하는 3차원 그래픽 어플리케이션을 개발할 수 있는 편의성과 효율성을 제공해 주고 있습니다.


향후 수년 내에 모바일 폰과 같은 디바이스가 지금의 데스크탑 PC는 물론 노트북을 대체할 것이라는 전망이 있습니다. 하지만 이런 전망이 현실화되기까지는 아직 해결 해야 할 과제가 많습니다. 하지만 모바일 폰이 PC나 노트북에서만 가능한 영역을 하나 하나 대체해 나갈 것이라는 사실은 부인할 수 없습니다. 이러한 사실을 놓고 볼 때 향후 사용자의 컴퓨팅 환경에서 데이터를 효과적으로 표현하고 사용자 경험(UX)를 극대화시키기 위한 사용자 인터페이스를 효과적으로 제공하기 위하여 3D 그래픽은 미래의 어플리케이션에서 필수불가결한 요소가 될 것입니다.


이 책은 자신이 개발하고 있는 모바일 어플리케이션에 3D 그래픽 기능을 체계적이고 효과적으로 추가할 수 있도록 모바일 3D 그래픽 API인 OpenGL ES와 M3G를 자세하고 명확하게 설명합니다. 또한 저자들의 경험을 통해 빠지기 쉬운 함정에 대한 해법을 제시해 주고 있습니다. 그리고 3D 그래픽에 대한 수학적인 내용을 꼼꼼히 설명하여 더 정교하게 3D 그래픽 API를 사용할 수 있도록 하였습니다.


특히 이 책의 저자들 모두가 OpenGL ES와 M3G의 명세서 정의에서부터 구현까지 참여했던 코어 개발자이며 아키텍쳐임과 동시에 모바일 3D 그래픽 분야의 리더들이라는 점에서 이 책의 가치가 더욱 빛납니다.


끝으로 이 책의 번역할 수 있는 기회를 준 사이텍미디어의 홍성신 대리님과 부족한 원고를 교정해주고 편집해준 사이텍미디어의 박경민님께 감사드립니다. 그리고 수개월동안 회사생활과 이 책의 번역을 함께 하며 항상 즐겁지만은 않았을 저에게 항상 밝은 모습으로 응원해 준 아내 지은이에게 끝없는 사랑과 감사를 전합니다.

Java와 C의 zip 압축 연산에 대한 퍼포먼스 비교

먼저 C의 zip 압축은 Jean-loup Gailly님이 만들어 공개한 zlib 1.2.2를 사용했습니다. C/C++에서 데이터의 압축에서 사용하는 압축 라이브러리는 흔히 이 zlib를 사용합니다.  그리고 Java에서 압축은 기본적으로 제공하는 java.util.zip.Deflater 클래스를 사용했습니다. 테스트를 한 이유는 Java가 C/C++에 비해서 얼마나 느릴까… 하는 기대였습니다. =_=;

Java와 C/C++ 모두 사용한 압축 데이터는 0.2메가 정도되는 jpg 파일로 했습니다. 그리고 Java와 C/C++ 모두 결과는 압축 레벨을 3으로 했을때 동일한 결과와 크기였으며 원본 크기에 비해 75% 정도의 압축되었습니다. 결과는 다음 같습니다. 첫번째 이미지는 Java의 결과이고.. 두번째는 C/C++의 결과입니다.

사용자 삽입 이미지
와우!! Java가 C/C++에 비해 상당히 느릴것으로 기대했는데… 그렇지 않았습니다. C/C++와 성능은 거의 비슷한 것으로 생각됩니다. 두 경우 모두 최악의 경우 0.016초정도 소요됩니다. 다만…. Java의 경우 가끔씩 튀는 부분이 있었는데.. 0.031초 정도 소요되는 부분이 가끔 나옵니다. 아마도 Java의 gc기능 때문이 아닌가… 가볍게 짐작해봅니다. 하지만 이런 부분은 제외하면 정말 C/C++과 같은 Native 컴파일러 못지 않은 성능이라고 판단됩니다.

아래는 Java에서 퍼포먼스 테스트로 사용했던 코드입니다.

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import java.io.*;

public class TestMain {
    public static void main(String[] args) 
        throws IOException, DataFormatException
    {
        FileInputStream fis = new FileInputStream("d:/a.jpg");
        ByteArrayOutputStream baos = new ByteArrayOutputStream(fis.available());
        byte [] buffer = new byte[512];
        int cntRead;
        while((cntRead=fis.read(buffer)) != -1) {
            baos.write(buffer, 0, cntRead);
        }

        byte[] compressedBytes = null;
        for(int i=0; i<20; i++) { // 20 times repeat..
            System.out.println("Performance Test Start...");
            long stime = System.currentTimeMillis();
 
            compressedBytes = Compress(baos.toByteArray());
   
            long etime = System.currentTimeMillis();
            System.out.println("Performance Test Result : " 
                + (etime-stime)+" MS.");
        }   
 
         FileOutputStream fos = new FileOutputStream("d:/a_java.jpg.zip");
         ByteArrayInputStream bais = new ByteArrayInputStream(compressedBytes);
         while((cntRead=bais.read(buffer)) != -1) {
             fos.write(buffer, 0, cntRead);
         }
    }

    private static byte[] Compress(byte[] bytesToCompress) throws IOException
    {
        Deflater compressor = new Deflater(3);
        compressor.setInput(bytesToCompress);
        compressor.finish();
 
        ByteArrayOutputStream bos = 
            new ByteArrayOutputStream(bytesToCompress.length);
 
        byte[] buf = new byte[bytesToCompress.length + 100];
        while (!compressor.finished())
        {
            bos.write(buf, 0, compressor.deflate(buf));
        }

        bos.close();
 
        return bos.toByteArray();
    }
}

대략 살펴보시면 위의 코드에는 IO에 대한 Buffer 기능과 같은.. 여전히 최적화의 여지가 남아 있습니다. 더 이상 제가 갖고 있는 “자바는 느리다”라는 선입견이 상당 부분 깨진 느낌입니다.

[GIS] ArcObjects, 도형의 좌표 구하기

ArcObjects를 통해 SHP 파일을 읽어서 만든 레이어를 화면상에 표시한 후… 이 레이어를 구성하는 도형(Shape) 좌표를 구하는 방법을 정리해 보았습니다. ArcObjects에서 제공하는 Map 컨트롤을 통해 SHP 레이어가 하나 추가되었다고 가정하겠습니다. 참고로 이 포스트는 레이어가 폴리곤 도형으로 구성된 레이어를 대상으로 합니다.

가장 먼저 해야할 일은 지도 컨트롤이 가지고 있는 레이어를 가져오는 일입니다. 가져올때 도형 정보에 접근해야 하므로 IFeatureLayer 인터페이스 타입으로 가져와야 합니다.

ESRI.ArcGIS.Carto.IFeatureLayer pFL;
pFL = axMapControl1.get_Layer(0) as ESRI.ArcGIS.Carto.IFeatureLayer;

이렇게 가져온 IFeatureLayer 변수인 pFL을 통해 각각의 Feature를 얻어오기 위해 IFeatureClass와 IFeatureCursor를 이용합니다.

ESRI.ArcGIS.Geodatabase.IFeatureClass pFClass;
pFClass = pFL.FeatureClass;

ESRI.ArcGIS.Geodatabase.IFeatureCursor pFCursor;
pFCursor = pFClass.Search(null, false);

이제 레이어를 구성하는 Feature를 읽을 수 있는 준비가 되었습니다. 아래의 반복문을 통해 각각의 Feature를 순회하면서 원하는 좌표를 읽게 됩니다.

ESRI.ArcGIS.Geodatabase.IFeature pFeature;            
while((pFeature=pFCursor.NextFeature()) != null) {
    ....
}

아래의 코드가 위의 코드의 반복문 사이(while문)에 들어가는 코드입니다. 도형은 Point의 집합이므로 IPointCollection 인터페이스 타입이 필요하며 각 포인트 좌표값과 관련 정보를 얻기 위해 IEnumVertex 인터페이스가 필요합니다.

    ESRI.ArcGIS.Geometry.IPointCollection pPC;
    pPC = pFeature.Shape as ESRI.ArcGIS.Geometry.IPointCollection;

    ESRI.ArcGIS.Geometry.IEnumVertex pEV = pPC.EnumVertices;

    ESRI.ArcGIS.Geometry.IPoint pPt;
    int outPartIndex;
    int vertexIndex;
    listBox1.Items.Add("FID: " + pFeature.OID);
    for(int i=0; i<pPC.PointCount; ++i) {
        pEV.Next(out pPt, out outPartIndex, out vertexIndex);
        listBox1.Items.Add("    Part Idx :" + outPartIndex + 
            " Vertex Idx : " + vertexIndex + " (" + pPt.X + "," + pPt.Y + ")");
    }

비록 이 포스트의 글은 폴리곤 레이어에 대한 내용이지만 이 보다 간단한 포인트나 폴리라인에 대해서도 쉽게 좌표를 읽을 수 있습니다. 마지막으로 아래는 위의 코드들을 실행했을때의 결과 입니다.

사용자 삽입 이미지