ArcGIS Engine空间分析之拓扑分析的实现
简单介绍:
拓扑学是一门研究几何图形位置关系的科学。
GIS所关注的拓扑主要集中在拓扑关系——存在于地理实体间的拓扑关系。
拓扑关系在GIS中起着描述两个地理实体的相对空间位置的重要作用。它是GIS空间实体之间最重要的关系之一,在GIS空间数据建模、空间查询、空间分析、空间推理、制图综合等过程中起着重要的作用。拓扑关系对GIS具有以下重要意义:
(1)不需要利用坐标或者计算距离,能够清楚地反映某一要素与另一要素的空间位置关系。
(2)某些空间分析功能是基于拓扑关系而实现的。例如,要求某条河流的流域面积、流经的城市,查询有哪些国家与某个国家相邻等等。
(3)在进行某些空间分析之前必须检查数据的拓扑关系的合理性。这样的空间分析功能有计算最佳路径、缓冲分析、裁剪、建立封闭多边形等。
拓扑元素是拓扑关系的描述单元。
GeoDatabase数据模型包括一般性的常见3类要素类:点状要素类、线状要素类和面状要素类。
在二维空间中,它们分别对应的是3种拓扑元素,即结点、弧和面域(多边形)。
拓扑关系是不考虑度量和方向的空间实体之间的空间关系,它讲究的是拓扑元素彼此间的相对位置关系。
拓扑邻接、拓扑关联、拓扑包含是三种最基本的拓扑关系。
最终效果图:
对于拓扑分析,其思路可以概括如下:
①创建拓扑数据集
②设置拓扑参数(拓扑规则)
③检查拓扑错误
④显示拓扑结果
①创建拓扑数据集
/// <summary> /// 创建拓扑数据集 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCreateTopo_Click(object sender, EventArgs e) { //设置指针处于等待状 this.Cursor = Cursors.WaitCursor; //创建拓扑数据集(前提是要素集内没有数据集) Global.GlobalTopology = create_topology(Global.pWorkSpace, "Road_Analysis", "Topology_Dataset"); //如果Flag为true则打开 if (Flag) { //打开拓扑数据集 Global.GlobalTopology = OpenToplogyFromFeatureWorkspace((IFeatureWorkspace)Global.pWorkSpace, "Road_Analysis", "Topology_Dataset"); //Flag为true表示已经存在拓扑数据集 MessageBox.Show("已经存在拓扑数据集"); //设置指针为默认状态 this.Cursor = Cursors.Default; //返回 return; } //创建要素类 IFeatureClass pTempFt = null; //向拓扑数据集中添加拓扑元素,可以添加多个 AddSingleElement(Global.GlobalTopology, "Road_Analysis", "南宁路网", out pTempFt); //添加单个要素的拓扑规则, 相同图层内的先不能相交 AddRuleToTopology(Global.GlobalTopology, esriTopologyRuleType.esriTRTLineNoIntersection, "NoIntersection", pTempFt); //Global.GlobalTopology将强转为IGeoDataset获得Extent IGeoDataset GDS = Global.GlobalTopology as IGeoDataset; //调用自定义方法添加拓扑规则 ValidateTopology(Global.GlobalTopology, GDS.Extent); MessageBox.Show("拓扑数据集创建成功!"); this.Cursor = Cursors.Default; }
一些参数:
/// <summary> /// 判断拓扑数据集是否存在,true表示存在拓扑数据集,false表示拓扑数据集为空 /// </summary> private bool Flag = false;
class Global { public static string GdbPath = Application.StartupPath + @"\网络分析\网络分析.mdb"; public static IWorkspace pWorkSpace; public static ITopology GlobalTopology; }
如果要创建拓扑数据集,调用create_topology函数
/// <summary> /// 创建拓扑数据集(前提是要素集内没有数据集) /// </summary> /// <param name="myWSp">工作空间</param> /// <param name="FtDSName">要素集名称</param> /// <param name="TopologyName">拓扑数据集名</param> /// <returns></returns> public ITopology create_topology(IWorkspace myWSp, string FtDSName, string TopologyName) { //实例化拓扑为null ITopology myTopology = null; try { //将工作空间强转成要素工作空间 IFeatureWorkspace pFtWsp = myWSp as IFeatureWorkspace; //通过要素工作空间打开名字为"FtDSName"的要素数据集 IFeatureDataset myFDS = pFtWsp.OpenFeatureDataset(FtDSName); //将要素数据集放在要素类容器中 IFeatureClassContainer myFCContainer = myFDS as IFeatureClassContainer; //将要素类容器强转成拓扑容器 ITopologyContainer myTopologyContainer = myFDS as ITopologyContainer; //通过拓扑容器创建一个新的拓扑 myTopology = myTopologyContainer.CreateTopology(TopologyName, myTopologyContainer.DefaultClusterTolerance, -1, ""); } catch (Exception ee) { //MessageBox.Show(ee.Message); //如果拓扑已经存在,则将Flag变为true Flag = true; //返回null return null; } //返回创建的myTopology return myTopology; }
注:如果创建拓扑出现问题,请参考【已解决】ArcGIS Engine无法创建拓扑的问题(CreateTopology)
如果拓扑数据集已经存在,调用OpenToplogyFromFeatureWorkspace函数
/// <summary> /// 打开拓扑数据集(如果拓扑数据集已经创建) /// </summary> /// <param name="featureWorkspace">工作空间</param> /// <param name="featureDatasetName">普通数据集</param> /// <param name="topologyName">拓扑集名</param> /// <returns>返回拓扑数据集</returns> private ITopology OpenToplogyFromFeatureWorkspace(IFeatureWorkspace featureWorkspace, string featureDatasetName, string topologyName) { //打开特征数据集 IFeatureDataset featureDataset = featureWorkspace.OpenFeatureDataset(featureDatasetName); //将featureDataset转换为ITopologyContainer ITopologyContainer topologyContainer = (ITopologyContainer)featureDataset; //ITopology get_TopologyByName(string Name); //打开拓扑 ITopology topology = topologyContainer.get_TopologyByName(topologyName); //返回拓扑 return topology; }
②设置拓扑参数(拓扑规则)
//向拓扑数据集中添加拓扑元素,可以添加多个 AddSingleElement(Global.GlobalTopology, "Road_Analysis", "南宁路网", out pTempFt);
/// <summary> /// 向拓扑数据集中添加拓扑元素 /// </summary> /// <param name="myTopology">拓扑数据集</param> /// <param name="DSName">数据集名</param> /// <param name="FtName">要素名</param> /// <param name="pFtClass">输出参与拓扑的单个元素</param> private void AddSingleElement(ITopology myTopology, string DSName, string FtName, out IFeatureClass pFtClass) { //打开工作空间 IFeatureWorkspace pFtWsp = Global.pWorkSpace as IFeatureWorkspace; //打开数据集 IFeatureDataset myFDS = pFtWsp.OpenFeatureDataset(DSName); //在数据集中打开要素 IFeatureClassContainer myFCContainer = myFDS as IFeatureClassContainer; IFeatureClass pTempFt = myFCContainer.get_ClassByName(FtName); pFtClass = pTempFt; //调用ITopology.AddClass方法添加要素 myTopology.AddClass(pTempFt, 5, 1, 1, false); }
//添加单个要素的拓扑规则, 相同图层内的先不能相交 AddRuleToTopology(Global.GlobalTopology, esriTopologyRuleType.esriTRTLineNoIntersection, "NoIntersection", pTempFt);
/// <summary> /// 添加单个要素的拓扑规则 /// </summary> /// <param name="topology">拓扑数据集</param> /// <param name="ruleType">拓扑规则</param> /// <param name="ruleName">规则名称</param> /// <param name="featureClass">参与制定规则的要素</param> private void AddRuleToTopology(ITopology topology, esriTopologyRuleType ruleType, string ruleName, IFeatureClass featureClass) { //实例化拓扑规则 ITopologyRule topologyRule = new TopologyRuleClass(); //拓扑规则 topologyRule.TopologyRuleType = ruleType; //规则名称 topologyRule.Name = ruleName; //规则面向的要素类 topologyRule.OriginClassID = featureClass.FeatureClassID; topologyRule.AllOriginSubtypes = true; ITopologyRuleContainer topologyRuleContainer = (ITopologyRuleContainer)topology; if (topologyRuleContainer.get_CanAddRule(topologyRule)) { //调用.AddRule方法添加规则 topologyRuleContainer.AddRule(topologyRule); } else { MessageBox.Show("规则添加失败, 不适用于拓扑集"); } }
③检查拓扑错误
//验证拓扑错误 ValidateTopology(Global.GlobalTopology, GDS.Extent);
/// <summary> /// 验证拓扑错误 /// </summary> /// <param name="topology">拓扑集</param> /// <param name="envelope">t拓扑集的Extent</param> private void ValidateTopology(ITopology topology, IEnvelope envelope) { //实例化一个Polygon存储Topology的Extent IPolygon localPolygon = new PolygonClass(); //获取Topology的外接矩形 ISegmentCollection segmentCollection = (ISegmentCollection)localPolygon; segmentCollection.SetRectangle(envelope); //赋值Topology的阴影区域 IPolygon polygon = topology.get_DirtyArea(localPolygon); if (!polygon.IsEmpty) { //赋值参数并Validate拓扑错误 IEnvelope areaToValidate = polygon.Envelope; IEnvelope areaValidated = topology.ValidateTopology(areaToValidate); } }
④显示拓扑结果
/// <summary> /// 显示拓扑结果 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnDisplayTopo_Click(object sender, EventArgs e) { //防止没有拓扑而创建图层对象 if(Flag) { //设置指针处于等待状 this.Cursor = Cursors.WaitCursor; //新建一个拓扑图层 ITopologyLayer pTpLayer = new TopologyLayerClass(); //将Global.GlobalTopology赋值给当前的拓扑图层的拓扑 pTpLayer.Topology = Global.GlobalTopology; //拓扑图层强转成图层 ILayer pLayer = (ILayer)pTpLayer; //将图层名字命名为"Topology_Dataset" pLayer.Name = "Topology_Dataset"; //将图层加到axMapControl1上 axMapControl1.AddLayer(pLayer); //设置指针为默认状态 this.Cursor = Cursors.Default; } }
总结:
谢谢观看!本人初学GIS二次开发,如果有不对的地方,请多多包涵!