基于ArcGIS Engine的任意多边形凸剖分算法

任意多边形凸剖分对于编程人员来说是经常遇到的问题,当然算法也很多,但是大多很复杂,如果从底层来编写,非常繁琐
下面介绍一种基于AE的方法,理解起来,编写起来都比较简单,供大家参考

算法思想:
1、首先找到该多边形的包罗矩形(IGeometry.Envelope)
2、然后将该多边形的顶点集合(IPointCollection)按照X坐标(或Y坐标)进行从小到大(或从大到小)排序
3、然后过排序后的多边形顶点从小到大(或从大到小)绘制竖直(或水平)的直线
4、绘制的直线与多边形边界相交,就将该多边形分割成为若干个凸多边形。

附VB.Net源码
''' <summary>
''' 得到任意多边形的剖分凸多边形集合
''' </summary>
''' <param name="pGeo">任意多边形</param>
''' <returns>剖分凸多边形集合</returns>
''' <remarks></remarks>
Private Shared Function GetSolidHatchs(ByVal pGeo As IGeometry) As IGeometryCollection
Dim pPoints As IPointCollection = pGeo
Dim pXs As New List(Of Double)
For i As Integer = 0 To pPoints.PointCount - 1
pXs.Add(pPoints.Point(i).X)
Next
'’对该多边形边界的所有点集合以X或Y为标准进行排序,用于画切割线
pXs.Sort()
Dim pGeos As IGeometryCollection = New Polygon
Dim pTopo As ITopologicalOperator = pGeo
Dim listCount As Integer = pXs.Count

Dim leftGeo As IGeometryCollection = New Polygon
Dim rightGeo As IGeometryCollection = New Polygon
For i As Integer = 0 To listCount - 1
If pTopo.Boundary.IsEmpty Then Continue For
If pXs(i) <= pTopo.Boundary.Envelope.XMin Or pXs(i) >= pTopo.Boundary.Envelope.XMax Then Continue For
Dim cutLine As IPolyline = New Polyline
Dim fromPoint As IPoint = New Point
fromPoint.PutCoords(pXs(i), pTopo.Boundary.Envelope.YMax)
Dim toPoint As IPoint = New Point
toPoint.PutCoords(pXs(i), pTopo.Boundary.Envelope.YMin)
''生成切割线
cutLine.FromPoint = fromPoint
cutLine.ToPoint = toPoint
''用切割线切割多边形
Try
pTopo.Cut(cutLine, leftGeo, rightGeo)
Catch ex As Exception
Continue For
End Try
''一条切割线切割出两个多边形,rightGeo是凸的,leftGeo继续用于切割
pTopo = leftGeo
For j As Integer = 0 To rightGeo.GeometryCount - 1
pGeos.AddGeometry(rightGeo.Geometry(j))
Next
Next
If Not rightGeo Is Nothing Then
For j As Integer = 0 To leftGeo.GeometryCount - 1
pGeos.AddGeometry(leftGeo.Geometry(j))
Next
End If
If pGeos.GeometryCount = 0 Then
For j As Integer = 0 To CType(pGeo, IGeometryCollection).GeometryCount - 1
pGeos.AddGeometry(CType(pGeo, IGeometryCollection).Geometry(j))
Next
End If
Return pGeos
End Function



通过线构造面(C# + ArcGIS Engine 9.2)


生成面之前的截图:
基于ArcGIS Engine的任意多边形凸剖分算法

生成为面之后的截图:
基于ArcGIS Engine的任意多边形凸剖分算法

从线生成面的方法代码:

///<summary>
///通过线创建面
///</summary>
///<paramname="pPolyline">线</param>
///<returns></returns>
IPolygonConstructPolygonFromPolyline(IPolylinepPolyline)
{
IGeometryCollectionpPolygonGeoCol
=newPolygonClass();

if((pPolyline!=null)&&(!pPolyline.IsEmpty))
{
IGeometryCollectionpPolylineGeoCol
=pPolylineasIGeometryCollection;
ISegmentCollectionpSegCol
=newRingClass();
ISegmentpSegment
=null;
objectmissing=Type.Missing;

for(inti=0;i<pPolylineGeoCol.GeometryCount;i++)
{
ISegmentCollectionpPolylineSegCol
=pPolylineGeoCol.get_Geometry(i)asISegmentCollection;
for(intj=0;j<pPolylineSegCol.SegmentCount;j++)
{
pSegment
=pPolylineSegCol.get_Segment(j);
pSegCol.AddSegment(pSegment,
refmissing,refmissing);
}
pPolygonGeoCol.AddGeometry(pSegCol
asIGeometry,refmissing,refmissing);
}
}
returnpPolygonGeoColasIPolygon;
}

调用示例:
ILayerpLayer=axMapControl1.get_Layer(1);
IFeatureLayerpFeatureLayer
=pLayerasIFeatureLayer;
IFeatureClasspFeatureClass
=pFeatureLayer.FeatureClass;
if(pFeatureClass.ShapeType==esriGeometryType.esriGeometryPolyline)
{
IFeatureCursorpFeatureCursor
=pFeatureClass.Search(null,false);
IFeaturepFeature
=pFeatureCursor.NextFeature();

ILayerpTargetLayer
=axMapControl1.get_Layer(2);
IFeatureLayerpTargetFeatureLayer
=pTargetLayerasIFeatureLayer;
IFeatureClasspTargetFeatureClass
=pTargetFeatureLayer.FeatureClass;
if(pTargetFeatureClass.ShapeType==esriGeometryType.esriGeometryPolygon)
{
IPolygonpPolygon
=null;
while(pFeature!=null)
{
IPolylinepPolyline
=pFeature.ShapeasIPolyline;
pPolygon
=ConstructPolygonFromPolyline(pPolyline);
if((pPolygon!=null)&&(!pPolygon.IsEmpty))
{
if(!pPolygon.IsClosed)
{
pPolygon.Close();
}
IFeaturepNewFeature
=pTargetFeatureClass.CreateFeature();
pNewFeature.Shape
=pPolygon;
pNewFeature.Store();
pFeature.Delete();
}
pFeature
=pFeatureCursor.NextFeature();
}
}
}
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography,
null,null);