问题描述:
已有点(point)图层,利用Arcengine求这些点的服务范围
解决思路:
点密集的地方,每个点的服务范围就小。点稀疏的地方,每个点的服务范围就大。可以用求泰森多边形的思路来求解。
简单说自己理解的Voronoi图的特点,这是一组多边形,这样一组多边形将整个平面分成N个区域,每个区域中包含一个POI点(Point of Information,信息点,也有说兴趣点),这个区域内所有的点,到这个POI点都比到其他POI点近。
Voronoi图与Delaunay三角剖分互为偶图,也就是一一对应。而Delaunay是Tin的最普及的实现形式,Arcgis本身给我们提供了TIN和Voronoi图的生成。
Arcengine里面TinClass、ITinNode两个类可以帮助我们实现,不懂tin和Voronoi实现算法也可以计算Voronoi多边形面积。
So,可以用这两个类来实现的。
编码思路:
1、遍历FeatureClass,得到MultipointClass类的Points
2、把Points逐一add进TinClass类实例,由这个类自己维护这个三角网
3、逐一去除三角网的节点,获取Area字段的信息。
两个重点的类:
TinClass
InitNew(IEnvelopepExtend); // 初始化: 用传过来的区域初始化点域,比如传图层的包围盒
AddPointZ(IPoint pPoint,int TagValue); //把点加进三角网中
ITinNode
IsInsideDataAre;//属性,判断它是不是数据域内的点,比如说我传的是图层的包围盒,那就是除了四个顶点之外的点,都是true
GetVoronoiRegion(IPolygon pClippintPolygon) //获取这个点对应的泰森多边形。传null,程序会用一个默认的矩形来裁剪的Voronoi区域,这个矩形比点区域大
贴代码
public bool POIcalculate( IFeatureLayer flayer) { message = String.Empty; if (flayer == null ) return false; IFeatureClass fc = flayer.FeatureClass; if (fc == null) return false; IFeatureCursor fCuror = fc.Search(null, false); MultipointClass mp = new MultipointClass(); object miss = Type.Missing; IFeature f = null; //从点图层获取点数据 while ((f = fCuror.NextFeature()) != null) { //sBar.StepProgressBar(); IPoint p = f.Shape as IPoint; mp.AddGeometry(p, ref miss, ref miss); } List<Double> areaList = new List<double>(); TinClass tin = new TinClass(); tin.InitNew(mp.Envelope); tin.StartInMemoryEditing(); IPointCollection pc = mp as IPointCollection; List<int> tinNodeIndex = new List<int>(); //遍历传过来的点集合,加到Tin里面 for (int i = 0; i < pc.PointCount; i++) { IPoint p = pc.get_Point(i); p.Z = 0; tin.AddPointZ(p, i); } //遍历节点,取到每个节点的面积,作为最终的服务范围 for (int i = 1; i <= tin.NodeCount; i++) { ITinNode node = tin.GetNode(i); if (!node.IsInsideDataArea)//除去包围盒的4个顶点 continue; areaList.Add((node.GetVoronoiRegion(null) as IArea).Area); } addToAreaField(fc, areaList); return true; }
因为要把值赋给每个POI点,所以最后有个addToAreaField()方法,用来赋值的,一起贴吧
//添加面积字段并赋值 private Boolean addToAreaField(IFeatureClass fc, List<double> values) { //新建area字段 String msg; FieldInfo VoronoiArea = GApplication.fieldMap[GApplication.VoronoiArea]; int areaIndex = Utility.addOrgetField(fc, VoronoiArea, out msg); if (areaIndex == -1) { message = msg; return false; } //赋值 IField field = fc.Fields.get_Field(areaIndex); IQueryFilter filter = new QueryFilterClass(); filter.SubFields = field.Name; int i = -1; ITable pTable = fc as ITable; ICursor pCursor = pTable.Update(filter, false); IRow pRow = null; int numcount = pTable.RowCount(null); while ((pRow = pCursor.NextRow()) != null && i++ < values.Count - 1) { pRow.set_Value(areaIndex, values[i]); pCursor.UpdateRow(pRow); } return true; }
相关TIPS:
最后还是要了解一下Tin和Voronoi的基本知识,虽然Arcgis实现了算法,基本的还是得知道的,参考自链接
http://blog.sina.com.cn/s/blog_5fe823a50100dun6.html《Delaunay三角网与Voronoi图 》
http://blog.sina.com.cn/s/blog_b25e55800102vbi2.html《Arcgis中构建不规则三角网(TIN)》
Tip1、TIN用来干嘛? 地面是不规则的,不是一个二维平面能够描述的,要引入空间这样一个概念。等高线就是一个描述描述空间分布特征的手段。Tin也是这样一种手段。它的定义:“Tin(不规则三角网)是通过不规则分布的采样数据点生成的连续三角面来逼近地形表面。” 大概是这样子:现在有一堆点,和周边连接起来形成三角形,点密集的地方,三角形小,点稀疏的地方,三角形大。就像等高线所描述的,等高线稀疏的地方陡,等高线密集的地方,坡度缓。
Tip2、怎样的三角网称作TIN? 上述三角形组合无穷多,而存在一种“最佳三角形”,能最好的描述地形变化。这种最佳三角形满足这样的条件:尽可能的保证三角形的三个角都是锐角,三角形的三条边近似相等,最小角最大化。
Tip3、Delaunay三角网和TIN的关系? Delaunay算法是最广泛采用的三角剖分算法,因为Delaunay三角网可以自动避免狭长三角形的产生,三角形插值可信度高。
Tip4、Delaunay和Voronoi的关系? Delaunay三角形是由与相邻Voronoi多边形共享一条边的相关点连接而成的三角形。Delaunay三角形的外接圆圆心是与三角形相关的Voronoi多边形的一个顶点。
Tips5、TIN更多的是应用到用z值(高程信息)的场景,这里的用法只是为了拿到每个节点对应的Voronoi的面积,数据本身不涉及高程信息。
最后上这两张图,它们可以清晰的描述由点和Delaunay三角网、Delaunay三角网到Voronoi多边形的联系:
左边是点数据,右边是对应的Delaunay三角网
实线是Delaunay三角网,虚线对应的Voronoi多边形