基于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)


生成面之前的截图:


生成为面之后的截图:


从线生成面的方法代码:

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

if ((pPolyline != null ) && ( ! pPolyline.IsEmpty))
{
IGeometryCollectionpPolylineGeoCol
= pPolyline as IGeometryCollection;
ISegmentCollectionpSegCol
= new RingClass();
ISegmentpSegment
= null ;
object missing = Type.Missing;

for ( int i = 0 ;i < pPolylineGeoCol.GeometryCount;i ++ )
{
ISegmentCollectionpPolylineSegCol
= pPolylineGeoCol.get_Geometry(i) as ISegmentCollection;
for ( int j = 0 ;j < pPolylineSegCol.SegmentCount;j ++ )
{
pSegment
= pPolylineSegCol.get_Segment(j);
pSegCol.AddSegment(pSegment,
ref missing, ref missing);
}
pPolygonGeoCol.AddGeometry(pSegCol
as IGeometry, ref missing, ref missing);
}
}
return pPolygonGeoCol as IPolygon;
}

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

ILayerpTargetLayer
= axMapControl1.get_Layer( 2 );
IFeatureLayerpTargetFeatureLayer
= pTargetLayer as IFeatureLayer;
IFeatureClasspTargetFeatureClass
= pTargetFeatureLayer.FeatureClass;
if (pTargetFeatureClass.ShapeType == esriGeometryType.esriGeometryPolygon)
{
IPolygonpPolygon
= null ;
while (pFeature != null )
{
IPolylinepPolyline
= pFeature.Shape as IPolyline;
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 );

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值