[GIS] ArcObjects, Graphic Element 추가하기

ArcObjects에서 제공하는 Map 컨트롤은 기본적으로 GraphicsContainer 자식 객체를 가지고 있으며 이 컨테이너에 사용자가 원하는 그래픽 요소를 추가할 수 있는 기능을 제공합니다. 추가할 수 있는 그래픽 요소는 생각할 수 있는 2차원 요소 대부분으로 포인트, 폴리라인, 폴리곤, 사각형, 타원 등입니다. 이 글은 이러한 그래픽 요소를 추가하는 방법를 폴리곤 그래픽 요소의 추가를 예로 들어 정리해 하겠습니다.

그래픽 요소의 구성은 크게 지오메트리(Geometry)와 심벌(Symbol)이며… 지오메트리는 정점으로 구성한 그래픽 요소의 뼈대로 생각할 수 있고 심벌은 그래픽 요소의 채움에 대한 색이나 투명도 그리고 외곽선의 굵기, 색상 등에 대한 정보입니다.

앞서 언급한 폴리곤 그래픽 요소를 추가하기 위하여 먼저 지오메트리를 구성하는 코드를 작성해 보면 다음과 같습니다.

ESRI.ArcGIS.Geometry.Point pPt1, pPt2, pPt3, pPt4;
pPt1 = new ESRI.ArcGIS.Geometry.Point();
pPt1.X = 100; pPt1.Y = 100;

pPt2 = new ESRI.ArcGIS.Geometry.Point();
pPt2.X = 900; pPt2.Y = 100;

pPt3 = new ESRI.ArcGIS.Geometry.Point();
pPt3.X = 900; pPt3.Y = 900;

pPt4 = new ESRI.ArcGIS.Geometry.Point();
pPt4.X = 100; pPt4.Y = 900;

object missing = Type.Missing;
ESRI.ArcGIS.Geometry.Polygon pPg;
pPg = new ESRI.ArcGIS.Geometry.Polygon();
pPg.AddPoint(pPt1, ref missing, ref missing);
pPg.AddPoint(pPt2, ref missing, ref missing);
pPg.AddPoint(pPt3, ref missing, ref missing);
pPg.AddPoint(pPt4, ref missing, ref missing);
pPg.AddPoint(pPt1, ref missing, ref missing);

사각형을 구성하는 4개의 좌표를 지정하기 위해 Point 타입의 변수 pPt1, pPt2, pPt3, pPt4의 X 그리고 Y에 좌표값을 지정합니다. 여기서는 사각형의 구성 좌표는 (100, 100)  (900, 100)  (900, 900)  (100, 900)입니다. 그리고 이렇게 지정한 좌표로 구성된 사각형 폴리곤을 구성하기 위해 Polygon 타입의 pPg 변수를 만들고 앞서 만든 4개의 좌표 변수를 추가합니다. 여기까지가 그래픽 요소의 지오메트리를 정의하는 방법이고… 다음으로 심벌을 정의하는 방법에 대해 정리해 보겠습니다.

폴리곤의 심벌을 간단히 생각해보면 채움과 외곽선으로 구분할 수 있습니다. 아래의 코드가 채움 심벌과 외곽선 심벌을 지정하는 코드입니다.

ESRI.ArcGIS.Display.IRgbColor pFillRGB;
pFillRGB = new ESRI.ArcGIS.Display.RgbColor();
pFillRGB.Red = 127;
pFillRGB.Green = 127;
pFillRGB.Blue = 127;

ESRI.ArcGIS.Display.IRgbColor pLineRGB;
pLineRGB = new ESRI.ArcGIS.Display.RgbColor();
pLineRGB.Red = 0;
pLineRGB.Green = 0;
pLineRGB.Blue = 0;

ESRI.ArcGIS.Display.ISimpleLineSymbol pSLS;
pSLS = new ESRI.ArcGIS.Display.SimpleLineSymbol();
pSLS.Color = pLineRGB;

ESRI.ArcGIS.Display.ISimpleFillSymbol pSFS;
pSFS = new ESRI.ArcGIS.Display.SimpleFillSymbol();
pSFS.Color = pFillRGB;
pSFS.Outline = pSLS;

채움에 대한 색상과 외곽선에 대한 색상을 지정하기 위하여 IRgbColor 타입의 변수 pFillRGB와 pLineRGB를 정의하고 이 변수에 대한 색상을 RGB 요소 값으로 지정합니다. 그리고 이렇게 만든 색상을 실제 심벌에 지정하기 위하여 외곽선 심벌 타입인 ISimpleLineSymbol로 pSLS 변수를 생성하고 이 변수의 Color 속성에 앞서 지정한 색상을 지정합니다. 마찬가지로 채움에 대한 ISimpleFillSymbol 변수인 pSFS를 생성하고 색상을 지정합니다. 여기서는 단순한 채움과 외곽선 스타일이므로 ISimpleFillSymbol과 ISimpleLineSymbol을 사용했지만 다양한 이미지 패턴 채움 등과 같은 복잡한 심벌은 또 다른 심벌 타입을 사용하게 됩니다.

이제 이렇게 생성한 심벌과 지오메트리를 폴리곤 요소로써 그래픽 컨테이너에 추가하는 방법은 아래와 같습니다.

ESRI.ArcGIS.Carto.PolygonElement pPE;
pPE = new ESRI.ArcGIS.Carto.PolygonElement();

pPE.Geometry = pPg as ESRI.ArcGIS.Geometry.IGeometry;

ESRI.ArcGIS.Carto.IFillShapeElement pFSE = pPE as ESRI.ArcGIS.Carto.IFillShapeElement;
pFSE.Symbol = pSFS;

axMapControl1.ActiveView.GraphicsContainer.AddElement(pPE, 0);
axMapControl1.ActiveView.Refresh();

1번과 2번 코드가 폴리곤 요소인 PolygonElement 타입의 pPE를 생성하는 코드이며 4번 코드와 5,6번 코드가 앞서 정의한 지오메트리와 심벌을 pPE 객체에 지정하는 코드입니다. 그리고 이렇게 만든 폴리곤 요소를 그래픽 컨터에너에 추가하는 코드가 6번이며 화면상에 그 결과를 반영하는 코드가 마지막 7번 코드입니다. 참고로 6번 코드의 AddElement의 2번째 인자는 z-order 값으로써 0이 가장 최상단에 그려지게 됩니다. 아래는 실행 결과입니다.

사용자 삽입 이미지

또한 앞의 코드를 통해 살펴본 폴리곤 요소와 지오메트리 그리고 심벌에 대한 클래스 관계도는 아래와 같습니다.

사용자 삽입 이미지

[GIS] ArcObjects, 속성값으로 쿼리(Query)하기

GIS의 강력한 기능 중에 하나는 속성 데이터에 기반한 공간적인 처리 및 가시화인데, 이 글은 ArcObjects에서 속성값 조건에 대해 쿼리(Query)하는 방법에 대해 설명하겠습니다. 일단…. 속성값에 대한 쿼리가 목적이므로 먼저 속성값에 접근할 수 있는 ITable 인터페이스에 접근할 필요가 있습니다. 다음은 d:\__data__ 폴더 안의 seoul.dbf 파일로부터 ITable 인터페이스의 구체 클래스 인스턴스를 얻는 코드입니다.

ESRI.ArcGIS.Geodatabase.IWorkspaceFactory pWF;
ESRI.ArcGIS.Geodatabase.IFeatureWorkspace pFW;

pWF = new ESRI.ArcGIS.DataSourcesFile.ShapefileWorkspaceFactory();
pFW = pWF.OpenFromFile("d:/__data__", 0) 
                as ESRI.ArcGIS.Geodatabase.IFeatureWorkspace;

ESRI.ArcGIS.Geodatabase.ITable pTable;
pTable = pFW.OpenTable("seoul");

ITable의 구체 클래스의 인스턴스인 pTable은 속성값으로 검색할 수 있는 매서드인 Search 함수를 가지고 있습니다. 이 Search 함수는 두개의 인수를 가지며 첫번째 인수의 타입은 IQueryFilter로써 SQL 문의 WHERE 절의 조건문을 지정하기 위해 사용됩니다. 그리고 두번째 인수는 검색 결과에 대한 Row에 대한 재활용 여부에 대한 bool 형입니다. 이에 대해서는 이 글의 마지막에 간단히 다시 설명하겠습니다.

속성값으로 쿼리하기 위하여 조건문을 만들기 위해서… 먼저 앞의 코드를 통해 오픈한 seoul.dbf 파일의 필드 구조를 알 필요가 있습니다. 힌트를 준다면 seoul.dbf의 속성 중의 하나는 SGG_NM으로써 서울시를 구성하는 행정구의 이름값이 저장되어 있습니다. 여기서는 행정구 이름에 ‘동’자가 들어가는 모든 Row를 검색하려고 합니다. 이런 조건을 위한 ITable의 Search의 첫번째 인자인 IQueryFilter의 CoClass(구체 클래스)의 정의는 다음과 같습니다.

ESRI.ArcGIS.Geodatabase.IQueryFilter pQF;
pQF = new ESRI.ArcGIS.Geodatabase.QueryFilter();
pQF.WhereClause = "SGG_NM LIKE '%동%'";

IQueryFilter의 WhereClause 프로퍼티가 바로 ‘그것’인데.. 일반적인 SQL의 SELECT 문의 WHERE 절의 바로 정확히 ‘그것’에 해당합니다. SQL문의 SELECT문을 알고 있는 개발자라면 아~!라는 탄식이 나올정도로 ArcObjects는 속성값으로 데이터를 쿼리하는 탁월한 방법을 사용하고 있습니다. 이렇게 만든 IQueryFilter를 이용하여 쿼리하는 코드는 다음과 같습니다.

ESRI.ArcGIS.Geodatabase.IFeatureCursor pFC;
pFC = pTable.Search(pQF, true) as ESRI.ArcGIS.Geodatabase.IFeatureCursor;

ITable의 Search 함수를 사용하며 검색 결과 Row는 IFeatureCursor 타입으로 반환됩니다. 검색 조건과 일치하는 Row를 얻기 위해 IFeatureCursor 타입의 인스턴스 변수인 pFC를 사용하는데.. 아래의 코드가 바로 그것이며, listBox1 이름의 ListBox 컨트롤에 그 결과를 채웁니다.

ESRI.ArcGIS.Geodatabase.IFeature pFeature;
int cntFields = pFC.Fields.FieldCount;

listBox1.Items.Clear();
pFeature = pFC.NextFeature();
while(pFeature != null) {
    for(int iField=0; iField

5번째 코드에서 가장 먼저 IFeatureClass의 NextFeature 매서드를 호출하여 첫번째 검색 결과의 Row에 해당되는 IFeature 클래스 타입의 인스턴스를 반환받고 첫번째 Row에 대한 값을 얻기 위하여 IFeature의 get_Value 매서드를 사용하여 값을 얻습니다. 그 다음 결과 Row를 얻기 위하여 다시 NextFeature를 호출합니다. NextFeature의 반환값이 null이면 더 이상 조건에 맞는 Row가 없다는 의미입니다. 실행 결과는 아래와 같습니다. 강동구, 성동구, 동작구, 동대문구와 같이 '동'자가 들어간 데이터만이 검색된 것을 알 수 있습니다.

사용자 삽입 이미지
끝으로 앞서 언급한... 이 글의 핵심 매서드인 ITable의 Search 매서드의 두번째 인자의 의미에 대해서 설명하면... 만약 true라면 IFeatureClass의 NextFeature의 결과에 대한 인스턴스를 재활용한다는 의미이며 false이면 재활용하지 않고 NextFeature를 호출할때 마다 새로운 인스턴스를 생성한다는 의미입니다. 이를 목적에 대해 생각해보면 true이면 Feature를 읽기 전용으로만 사용해야 하며 false일 경우 IFeature를 통해 속성값을 변경할 수 있습니다.