2010년 2월 22일 월요일

[ArcObjects]다양한 Geometry 버퍼(Buffer) 연산들

벡터 공간정보의 근린연산(proximity analysis)을 수행하기 위해서는 Geometry에 대한 Buffer 연산이 필수적이다. 버퍼 연산을 이용하여 공간상에서 주어진 지점과 주변객체들의 탐색 및 관계를 파악할 수 있다.
지난 시간의 Geometry Union에 이어 Geometry의 Buffer 연산에 대해 알아보기로 한다. Geometry의 버퍼연산은 다음 그림을 통해 이해하도록 하자.

※ 그림출처: VIVID Solution, 2004, JTS Topology Suite Developer’s Guide, pp.7-8

▣ ArcObjects에서의 Buffer제공 인터페이스 개요
ITopologicalOperator의 Buffer Method
 - ArcObjects에서 가장 기본적인 Buffer 기능
 - End cap style, Buffer side 등의 옵션을 사용자가 정의할 수 없음
 - 여기에서 참조: ITopologicalOperator

IBufferConstruction Interface
 - ArcGIS 9.3 버전에서 새로 추가된 인터페이스
 - IBufferConstructionProperties 인터페이스로 다양한 버퍼 옵션(EndOption, SideOption, ExplodeBuffers, OutsideOnly, GenerateCurves, UnionOverlappingBuffers, DensifyDeviation) 제공
 - 다수의 Geometry를 효율적으로 버퍼링
 - 개별 Geometry별로 서로다른 버퍼거리를 사용하여 버퍼링 가능
 -
Polyline 버퍼는 left, right 버퍼 가능
 - Polygon의 경우 Polygon의 Interior ring은 버퍼연산시 제외 가능
 - 여러 Geometry 버퍼시 겹치는(Overlap) 지역의 Dissolve 적용 여부 설정 가능
 -
geographic coordinate system을 사용하는 Geometry의 경우에 True geodesic 가능
 - Geometyr 유형이 다른 여러 Geometry를 동시에 버퍼 가능
 - 하나의 Geometry에 대해 동시에 다중 버퍼 가능
 - ARCTMPDIR(일반적으로 System의 Temp 폴더)내 임시 파일 생성 및 버퍼링 후 제거
 - 여기에서 참조: IBufferConstruction

IGeometryBridge의 ConstructBuffers Method
 - 하나의 Geometry에 대해 동시에 다중 버퍼를 생성하며 ITopologicalOperator의 Buffer를 각각 호출하는 것보다 효율적
 - 여기에서 참조: IGeometryBridge
ITopologicalOperator
다음 예는 포인트(0,0)에서 100의 거리만큼 버퍼를 수행하는 코드로 Buffer의 일반적인 사용법이다.

IPoint basePoint = new ESRI.ArcGIS.Geometry.PointClass();
basePoint.PutCoords(0, 0);
ITopologicalOperator topoOpt = (ITopologicalOperator)basePoint;
IPolygon bufferPolygon = (IPolygon)topoOpt.Buffer(100.0);
IArea baseArea = (IArea)bufferPolygon;
System.Diagnostics.Debug.WriteLine(baseArea.Area);
IBufferConstruction
다음 예는 위 ITopologicalOperator의 결과와 동일한 결과를 반환한다.

IPoint basePoint = new ESRI.ArcGIS.Geometry.PointClass();
basePoint.PutCoords(0, 0);

IBufferConstruction bufferConstruction = new BufferConstruction()
IPolygon bufferPolygon = (IPolygon)bufferConstruction.Buffer(basePoint, 100.0);

IArea baseArea = (IArea)bufferPolygon;
System.Diagnostics.Debug.WriteLine(baseArea.Area);
다음 예는 FeatureClass에서 ObjectID가 1, 2, 3인 피쳐로 Geometrybag을 생성 후 다중 버퍼 후 면적을 확인하는 코드이다. IBufferConstructionProperties 인터페이스의 멤버 적용을 확인하면 된다.
IFeatureClass featureClass = GetFeatureClass();

IGeometryCollection geometryBag = new GeometryBagClass();
IGeometryBag inputGeometries = (IGeometryBag)geometryBag;
inputGeometries.SpatialReference = ((IGeoDataset)featureClass).SpatialReference;
object missingObj = Type.Missing;

IFeatureCursor afCursor = featureClass.GetFeatures(new int[] {1, 2, 3}, true);
IFeature aFeature = null;
while ((aFeature = afCursor.NextFeature()) != null)
{
    geometryBag.AddGeometry(aFeature.ShapeCopy, ref missingObj, ref missingObj);
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(afCursor);

//ConstructBuffer 
IBufferConstruction ipBufCon = new BufferConstructionClass();

IBufferConstructionProperties ipBufConProp = (IBufferConstructionProperties)ipBufCon;
//defaults = esriBufferRound
ipBufConProp.EndOption = esriBufferConstructionEndEnum.esriBufferRound;  
//defaults = esriBufferFull
ipBufConProp.SideOption = esriBufferConstructionSideEnum.esriBufferFull; 
//defaults = false
ipBufConProp.ExplodeBuffers = false; 
//defaults = false
ipBufConProp.OutsideOnly = false; 
//defaults = true
ipBufConProp.GenerateCurves = true; 
//defaults = false
ipBufConProp.UnionOverlappingBuffers = false;
//The maximum distance between a line connecting two buffer curve points and the true curve 
//defaults to -1, indicating 1000 * xy tolerance of spatial reference of input geometries
ipBufConProp.DensifyDeviation = -1;  

IGeometryCollection bufferResults = new GeometryBagClass();
ipBufCon.ConstructBuffers((IEnumGeometry)inputGeometries, 1000, bufferResults);

for (int k = 0; k < bufferResults.GeometryCount; k++)
{
    IArea ipArea = (IArea)bufferResults.get_Geometry(k);

    System.Diagnostics.Debug.WriteLine(ipArea.Area);
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(ipBufCon);
IGeometryBridge
다음 예는 sourceGeometry를 100 ~ 500(미터 단위 가정)까지 100미터 간격으로 다중 버퍼 수행 후 면적을 확인하는 코드이다.
IGeometry sourceGeometry = GetGeometry();

ITopologicalOperator2 ipInputTopoOpt = (ITopologicalOperator2)sourceGeometry;

double[] distanceArray = new double[] {100, 200, 300, 400, 500};

IGeometryBridge ipGeomBridge = new GeometryEnvironmentClass();
IEnumGeometry ipEnumGeom = ipGeomBridge.ConstructBuffers(ipInputTopoOpt, ref distanceArray);
ipEnumGeom.Reset();

IArea ipArea = (IArea)ipEnumGeom.Next();
while (ipArea != null)
{
    System.Diagnostics.Debug.WriteLine(ipArea.Area);
    ipArea = (IArea)ipEnumGeom.Next();
}
▣ JTS Topology SuiteJTS에 보면 GeometryCollection에서 Buffer 메쏘드 호출할 때 0값을 설정하면 Union과 같은 결과를 얻을 수 있는데, ArcObjects의 IBufferConstruction은 이러한 처리는 못하나보다..

참고: Using union to combine a Collection of Geometry

JTS Topology Suite란?
Java 기반의 2D Geometry API로 Geometry들에 대한 공간관계 및 처리기능을 제공하며, JTS의 특징은 다음과 같다:

 * Open Geospatial Consortium Simple Features Specification for SQL 수용
 * 빠르고 견고한 2D 기반 공간관련 알고리즘 구현 및 제공
 * 100% 순수 JavaTM로 구현
 * LGPL 라이센스를 따르는 Open Source 라이브러리
 * GEOS(Geometry Engine, Open Source, JTS의 C++ 포팅), NTS(Net Topology Suite, JTS의 .NET C# 포팅) 등 Open Source GIS 엔진에서 대부분 활용하는 핵심 Geometry Engine


JTS에 대한 더 많은 정보는 여기에서 확인하면 된다.
* VIVID Solution: JTS Topology Suite
* Tsusiat Software: JTS Topology Suite