ArcGIS二次开发- 线段两侧缓冲N距离

ArcGIS二次开发-

线段两侧缓冲N距离

 

一、    开发环境;

   VS2010+ArcGIS10.1

二、    问题描述:

   存在一个要素类(为线要素类),将要素类中每个线要素沿两侧缓冲(ArcGIS中的缓冲不一样,ArcGIS在线段断头处是用起始和终点为圆心绘制了一个扇形)

   PS:一开始是想用纯粹底层来写的但是有一个地方不会(后面遇到了在提出来)。

 

三、    问题情况:

Q1:简单折线-即折线只有一段,也就是线段的情况。数据如下:

ArcGIS二次开发- 线段两侧缓冲N距离

这种情况下便是获取线的两个端点做与线段的垂线,并在两侧获取N距离的点,如此获得4个点,依次连接便可以获取最后缓冲的面,效果如下:




ArcGIS二次开发- 线段两侧缓冲N距离

















 

Q2:连续的折线(折角为钝角),数据情况如下:

ArcGIS二次开发- 线段两侧缓冲N距离

解决方法一:将折线L的两个顶点连接,生成过程线段A,线段A向两侧缓冲N距离,获得缓冲H方向,便利折线L的每一个端点,使端点根据缓冲方向H扩展N距离,将有序的缓冲后的端点连接,生成数据。效果如下:

ArcGIS二次开发- 线段两侧缓冲N距离

从上述方法来看数据是缓冲了,但是由于数据是折线在折点出都是钝角,所以粗略来看生成的数据看上去是符合要求的。但是我们仔细想想在这种情况下,折线的折点出,在优弧方应该是圆弧的,如图应该是下面的效果:

ArcGIS二次开发- 线段两侧缓冲N距离

而且该种方法,在数据存在折点处为锐角或有相交的情况时也会出现非常尴尬的局面,如下为这两种数据的范例:

ArcGIS二次开发- 线段两侧缓冲N距离

如下为数据按照解决方法一缓冲后的效果,很明显可以看出存在问题。 ArcGIS二次开发- 线段两侧缓冲N距离

解决方法二:在解决方法一的基础上进行了一定的修改,具体步骤如下:

Setp1:将折线数据转换为线段的数组,每组线段按照解决方法一的方法获取出四个顶点。

Setp2:获取出的四个顶点,按照顺序添加到两个数组中,在折线一侧的数据放置到同意数组中,当然这个数组要按照顺序存放。

Setp3:有上述两步我们可以得到3个点数组,2个缓冲后的点数组,1个原本折线的折点数组。首先我们申明一个面数组PArr用来存储面,根据3个数组,根据如下方法组成矩形,数据是否存在相交,若不存在相交,则根据顶点以及原点生成扇形将其添加到面数组PArr中并将两个矩形添加到Parr中,若存在相交则只将两个矩形添加到Parr中。

Step4:根据第三步生成的面数组PArr,将面数组PArr合并获取出来的面便是缓冲后的数据。

ArcGIS二次开发- 线段两侧缓冲N距离

上述步骤中,本人遇到的麻烦以及解决方法:

l  每一条线段如何获取出四个顶点?

从数学上可以采用两种方法(PS:目前本人能力有限只知道如下两种,勿喷):斜率即直线方程和向量的方式,我在我大学论文也是解决这类问题,采用的是斜率的方式,在这个问题上我便随意的采用向量的方式。

PS:感觉向量的方式只用把公式推导出来便可以,斜率比较复杂一点,而且在计算机中数值的存储是有位数的所以很容易出现精度缺失的问题。

l  判断两条线段是否有交点?

既然上一个问题采用了向量的方式,所以在这个问题上我也采用了向量的方式。

l  判断线段生成的4个定点如何划分到两个点数组中?

根据向量获取出点后,生成的点与缓冲原点连成的向量根据象限来划分。

l  两个面图形的合并?

这个本来想自己实现的,但是看了一下实现起来有点复杂,所以直接使用了ArcGIS平台二次开发的合并实现的。出于时间以及数据本来要用ArcGIS打开。所以直接使用了ArcGIS

 

附录:一些公式的推导过程,这里就直接在草稿纸上进行,进行后拍照贴在文档上。

公式求解1:线段四个缓冲顶点的计算方法:
ArcGIS二次开发- 线段两侧缓冲N距离

ArcGIS二次开发- 线段两侧缓冲N距离

想了想其他公式和这个差不多,就不推算了,无非用到了一些向量的基本特性。


2.ArcEngine提供了平头缓冲(即上述功能、PS:上述功能略微存在问题)。

1)使用GP,工具中参数可以设置为平头缓冲

2)使用ArcEngine接口

CreateLineBuffer(xzdwShape as IPolyline, kd / 2, esriBufferConstructionEndEnum.esriBufferFlat);

public static IPolygon CreateLineBuffer(IGeometry pGeometry, double UnitLength, esriBufferConstructionEndEnum pesriBufferConstructionEndEnum)
        {
            IEnumGeometry pEnumGeo = new GeometryBagClass();
            IGeometryCollection pGeoColl = pEnumGeo as IGeometryCollection;
            pGeoColl.AddGeometry(pGeometry);
            IBufferConstruction pBuffer = new BufferConstructionClass();
            IBufferConstructionProperties pBufferConstructionProperties = pBuffer as IBufferConstructionProperties;
            pBufferConstructionProperties.EndOption = pesriBufferConstructionEndEnum;
            IGeometryCollection pOutputBuffer = new GeometryBagClass();
            pBuffer.ConstructBuffers(pEnumGeo, UnitLength, pOutputBuffer); 
            IGeometry pOutGeometry = null;
            ITopologicalOperator pUnionBufferTopo = null;
            for (int i = 0; i < pOutputBuffer.GeometryCount; i++)
            {
                IGeometry pBufferChildGeo = pOutputBuffer.get_Geometry(i);
                if (pUnionBufferTopo == null)
                {
                    pUnionBufferTopo = pBufferChildGeo as ITopologicalOperator;
                }
                else
                {
                    pBufferChildGeo = pUnionBufferTopo.Union(pBufferChildGeo);
                    pUnionBufferTopo = pBufferChildGeo as ITopologicalOperator;
                }
            }
            pUnionBufferTopo.Simplify();
            pOutGeometry = pUnionBufferTopo as IGeometry;
            return pOutGeometry as IPolygon;
        }