9.2. 空間拓撲運算
9.2.1. ITopologicalOperator接口
通過一系列基於一個或者多個幾何圖形中點間的邏輯比較,然后返回另外一些幾何圖形,這個過程就是空間幾何圖形的拓撲運算。
空間幾何圖形的拓撲運算包括裁切(Clip)、凸多邊形(Convex hull)、切割(Cut)、差分(Difference)、交集(Intersect)、對稱差分(又稱為異或,Symmetric difference)和並集(Union)等,這些拓撲運算在ITopologicalOperator接口中定義,在GeometryBag、Multipoint、Point、Polygon、Polyline類中實現。
注意ITopologicalOperator接口的方法僅僅能使用在高級幾何對象上,即Point、Multipoint、Polyline和Polygon;如果要在低級的幾何對象上如Segment、Path或Ring上使用,則需要先組合為高級別幾何對象才行。
ITopologicalOperator::Boundary可以返回一個幾何對象的邊界,邊界的維度比源對象要低一維。
ITopologicalOperator::Buffer可以給一個高級別幾何對象產生一個緩沖區,無論是點、多邊形還是多義線,他們的緩沖區都是一個具有面積的幾何對象。
ITopologicalOperator::Clip方法可以將一個幾何對象使用一個包絡線來進行裁切,裁切的結果為幾何對象被包絡線包圍的部分。
ITopologicalOperator::ConstructUnion方法可以將一個幾何對象的枚舉(包含了多個幾何對象的枚舉值)與同維度的單個幾何對象合並,這種方法在大量幾何對象合並的時候是非常有效的;Union方法則可以合並兩個同維度的單個幾何對象,合並后的兩個單個幾何對象將變成一個幾何對象。
ITopologicalOperator::ConvexHull方法可以產生一個幾何圖形的最小的邊框凸多邊形。
ITopologicalOperator::Cut方法指定一條切割曲線和一個幾何圖形,經過切割運算后把幾何圖形分為左右兩部分,左右兩部分是相對曲線的方向而言;注意,點和多點是不能被切割的,而折線和多邊形只有與切割曲線相交時才能進行切割運算。
ITopologicalOperator::Difference方法可以產生兩個幾何對象的差集。如A是源對象,B是參與運算的幾何對象,則C是A減去A與B的交集后剩下的部分;而SymmetricDifference(對稱差分)方法則是將A與B的並集減去A與B的交集部分。
ITopologicalOperator::Intersection則可以返回兩個維度幾何形體對象的交集,即兩個對象重合部分。
參與空間拓撲運算的幾何形體,必須是拓撲上簡單的(topologically simple),否則會產生esriGeometryError536錯誤。
當幾何形體自上次驗證之后並未發生變化,那么IsKnowSimple屬性返回True;而IsSimple才是實際上驗證幾何形體是不是拓撲上簡單的。因此在使用IsSimple之前檢驗IsKnownSimple是更有效的,特別是在循環里,如下代碼:
IEnumGeometry pEnumGeom; pEnumGeom = pGeometryBag as IEnumGeometry; ITopologicalOperator pTopoOp; pTopoOp = pEnumGeom.Next() as ITopologicalOperator; while ( pTopoOp != null) { //首先驗證IsKnownSimple因為它速度更快 //在枚舉特別大的時候這樣更節約時間 if (!( pTopoOp.IsKnownSimple)) { if (!( pTopoOp.IsSimple)) pTopoOp.Simplify(); } pTopoOp = pEnumGeom.Next()as ITopologicalOperator; }
ITopologicalOperator::Simplify方法可以讓一個幾何對象變得在拓撲上一致,例如在一個PointCollection中,它可以讓所有的重合點(即兩個點擁有相同坐標值)被移除(出發擁有不同的屬性);對於SegmentCollection,它將移除重合的線段,而相交的線段會變成非相交的線段(即在相交點處產生一個頂點);對於Polygon而言,所有相交的環將被移除,所有的內外的方向將被修正,未封閉的環將被封閉,如圖
9.2.2. 開發實例 -- 緩沖區查詢
pActiveView = axMapControl1.ActiveView; pMap = axMapControl1.Map; IFeatureLayer pFeatureLayer = pMap.get_Layer(1) as IFeatureLayer; IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass; //鼠標點擊Map的點 IPoint pPoint = pActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(e.x, e.y); //對點對象做緩沖區運算 ITopologicalOperator pTopo; pTopo = pPoint as ITopologicalOperator; IGeometry pBuffer; pBuffer = pTopo.Buffer(4); IGeometry pGeometry = pBuffer.Envelope; //創建空間過濾器 ISpatialFilter pSpatialFilter; pSpatialFilter = new SpatialFilterClass(); pSpatialFilter.Geometry = pGeometry; //綁定空間過濾關系 switch (pFeatureClass.ShapeType) { case esriGeometryType.esriGeometryPoint: pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains; break; case esriGeometryType.esriGeometryPolyline: pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelCrosses; break; case esriGeometryType.esriGeometryPolygon: pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; break; } IFeatureSelection pFeatureSelection; pFeatureSelection = pFeatureLayer as IFeatureSelection; pFeatureSelection.SelectFeatures(pSpatialFilter, esriSelectionResultEnum.esriSelectionResultNew, false); ISelectionSet pFeatSet; pFeatSet = pFeatureSelection.SelectionSet; ICursor pCursor; pFeatSet.Search(null, true, out pCursor); IFeatureCursor pFeatureCursor = pCursor as IFeatureCursor; IFeature pFeature = pFeatureCursor.NextFeature(); //遍歷所有符合要求的要素,將它們加入要素選擇集中 while (pFeature != null) { //將當前的圖層加入當前圖層的要素選擇集 pMap.SelectFeature(pFeatureLayer, pFeature); pFeature = pFeatureCursor.NextFeature(); } pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);