基于C#的ArcEngine二次开发22:要素拓扑检查

目录

1 拓扑检查

1.1 拓扑检查的基本流程

1.2 拓扑检查代码

1.2.1 checkTopologyError

1.2.2 AddRuleToTopology

1.2.3 ValidateTopology

1.2.4 调用代码及效果

2 拓扑关系枚举

2.1 将文字描述转化为拓扑规则枚举对象

2.2 根据拓扑关系ID获取拓扑描述

X 异常处置

X.1 Error creating topology:-2147220960 Message:应用程序未获得创建或修改此类型数据的方案的许可

X.1.1异常描述

X.1.2 解决方案

X.2 Error creating topology:-2147220960 Message:尝试打开的数据库已被机器....以排他方式打开

X.2.1 异常描述

X.2.2 解决办法

X.3 从其他地方抄来的关于许可的说明

官方参考


先介绍一个ArcGIS拓扑检查的坑:

要素拓扑检查会修改原始数据,比如两条线间距为0.009米,实际不相交;如果容差设为0.1米,经过拓扑检查之后,会将此处融合并导致要素相交,如下图:

基于C#的ArcEngine二次开发22:要素拓扑检查_第1张图片

面对此种情形,我们应该在ArcCatalog中,新建 --> FeatureClassSet,设置更小的容差:

基于C#的ArcEngine二次开发22:要素拓扑检查_第2张图片

然后,将要检查的数据拷贝到该要素数据集中,然后在执行拓扑检查即可;注意两者的投影坐标系必须一致。


1 拓扑检查

1.1 拓扑检查的基本流程

基于C#的ArcEngine二次开发22:要素拓扑检查_第3张图片

1.2 拓扑检查代码

1.2.1 checkTopologyError

        /// 
        /// 检查要素层中存在的拓扑错误
        /// 
        /// 工作空间名称
        /// 数据集名称
        /// 要素类名称
        /// 拓扑要素层名,拓扑检查结果记录在该层中
        public void checkTopologyError(string wsPath, string dsPath, string feaPath, string topologyName)
        {
            // Open the workspace and the required datasets.
            Type factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.AccessWorkspaceFactory");
            //ESRI.ArcGIS.DataSourcesGDB
            IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactory();

            //1. 打开数据集文件
            IWorkspace workspace = workspaceFactory.OpenFromFile(wsPath, 0);
            IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)workspace;

            //2. 打开数据集文件
            IFeatureDataset featureDataset = featureWorkspace.OpenFeatureDataset(dsPath);

            //3. 向拓扑集中添加要素层
            IFeatureClass LRDLlayer = featureWorkspace.OpenFeatureClass(feaPath);
            

            //4. 设置拓扑处理对数据集的独占权限
            ISchemaLock schemaLock = (ISchemaLock)featureDataset;//注意此时不能使用ArcGIS再打开这个数据集
            try
            {
                schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);

                //5. 拓扑处理
                //5.1 创建拓扑容器
                ITopologyContainer2 topologyContainer = featureDataset as ITopologyContainer2;

                //5.2 向拓扑容器中添加拓扑结果层
                //判断当前命名的拓扑是否存在,如果存在,删除
                bool bTopExists = (featureDataset.Workspace as IWorkspace2).get_NameExists(esriDatasetType.esriDTTopology, topologyName);
                if (bTopExists)
                {
                    ITopology topologyTemp = topologyContainer.get_TopologyByName(topologyName);
                    //删除拓扑
                    IDataset pDatasetTemp = (IDataset)topologyTemp;
                    pDatasetTemp.Delete();
                    Marshal.ReleaseComObject(pDatasetTemp);
                }

                ITopology2 topology = topologyContainer.CreateTopology(topologyName,
                    topologyContainer.DefaultClusterTolerance, -1, "") as ITopology2;

               
                //5.3 添加参与拓扑运算的数据层
                topology.AddClass(LRDLlayer, 5, 1, 1, false);

                //5.4 添加拓扑规则
                AddRuleToTopology(topology, esriTopologyRuleType.esriTRTLineNoDangles, "线要素不允许有悬挂点", LRDLlayer);
                AddRuleToTopology(topology, esriTopologyRuleType.esriTRTLineNoPseudos, "线要素不允许有伪节点", LRDLlayer);
                AddRuleToTopology(topology, esriTopologyRuleType.esriTRTLineNoIntersectOrInteriorTouch, "线要素不能重叠或内部接触", LRDLlayer);
                AddRuleToTopology(topology, esriTopologyRuleType.esriTRTLineNoSelfIntersect, "线要素不能自相交", LRDLlayer);
                //5.5 拓扑验证
                IGeoDataset geoDataset = (IGeoDataset)topology;
                IEnvelope envelope = geoDataset.Extent;
                ValidateTopology(topology, envelope);
            }
            catch (COMException comExc)
            {
                throw new Exception(String.Format("Error creating topology: {0} Message: {1}", comExc.ErrorCode, comExc.Message), comExc);
            }
            finally
            {
               schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
            }
            MessageBox.Show("拓扑检查完毕", "提示信息");
        }

1.2.2 AddRuleToTopology

        /// 
        /// 增加拓扑规则
        /// 
        /// 拓扑集
        /// 拓扑规则
        /// 规则名称
        /// 要素类
        public void AddRuleToTopology(ITopology topology, esriTopologyRuleType ruleType,
            String ruleName, IFeatureClass featureClass)
        {
            // Create a topology rule.
            ITopologyRule topologyRule = new TopologyRuleClass();
            topologyRule.TopologyRuleType = ruleType;
            topologyRule.Name = ruleName;
            topologyRule.OriginClassID = featureClass.FeatureClassID;
            topologyRule.AllOriginSubtypes = true;

            // Cast the topology to the ITopologyRuleContainer interface and add the rule.
            ITopologyRuleContainer topologyRuleContainer = (ITopologyRuleContainer)topology;
            if (topologyRuleContainer.get_CanAddRule(topologyRule))
            {
                topologyRuleContainer.AddRule(topologyRule);
            }
            else
            {
                throw new ArgumentException("Could not add specified rule to the topology.");
            }
        }

1.2.3 ValidateTopology

        //拓扑有效性检查
        public void ValidateTopology(ITopology topology, IEnvelope envelope)
        {
            // Get the dirty area within the provided envelope.
            IPolygon locationPolygon = new PolygonClass();
            ISegmentCollection segmentCollection = (ISegmentCollection)locationPolygon;
            segmentCollection.SetRectangle(envelope);
            IPolygon polygon = topology.get_DirtyArea(locationPolygon);
            // If a dirty area exists, validate the topology.    if (!polygon.IsEmpty)
            {        // Define the area to validate and validate the topology.
                IEnvelope areaToValidate = polygon.Envelope;
                IEnvelope areaValidated = topology.ValidateTopology(areaToValidate);
            }
        }

1.2.4 调用代码及效果

        private void buttonExecute_Click(object sender, EventArgs e)
        {
            try
            {                
                //---------------------------检查拓扑错误-------------------------------------
                string inPath = textBoxInput.Text;
                string ouPath = textBoxOutput.Text;
                if (System.IO.File.Exists(inPath))
                {
                    checkTopologyError(inPath, "Topology", "LRDL", "TopologyCheck1");
                }
                //------------------------------------------------------------------------------
            }
            catch (Exception ex)
            {
                MessageBox.Show("触发异常操作:" + ex.ToString(), "执行失败");
            }
        }
基于C#的ArcEngine二次开发22:要素拓扑检查_第4张图片 拓扑检查结果

2 拓扑关系枚举

2.1 将文字描述转化为拓扑规则枚举对象

        /// 
        /// 根据错误的中文描述转换成esri拓扑枚举
        /// 
        /// 拓扑类型
        /// ESRI.ArcGIS.Geodatabase下的拓扑规则枚举类
        private esriTopologyRuleType PRV_ConvertTopologyRuleType(TopoErroType IN_TopoRuleType)
        {
            esriTopologyRuleType Temp_TopoRuleType;
            switch (IN_TopoRuleType)
            {
                case TopoErroType.面要素之间无空隙:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaNoGaps;
                    break;
                case TopoErroType.任何规则:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAny;
                    break;
                case TopoErroType.要素大于最小容差:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTFeatureLargerThanClusterTolerance;
                    break;
                case TopoErroType.面要素间无重叠:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaNoOverlap;
                    break;
                case TopoErroType.第二个图层面要素必须被第一个图层任一面要素覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaCoveredByAreaClass;
                    break;
                case TopoErroType.面要素必须只包含一个点要素:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaContainOnePoint;
                    break;
                case TopoErroType.两图层面要素必须互相覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaAreaCoverEachOther;
                    break;
                case TopoErroType.第一个图层面要素必须被第一个图层任一面要素包含:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaCoveredByArea;
                    break;
                case TopoErroType.图层间面要素不能相互覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaNoOverlapArea;
                    break;
                case TopoErroType.线要素必须跟面图层边界的一部分或全部重叠:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineCoveredByAreaBoundary;
                    break;
                case TopoErroType.点要素必须落在面要素边界上:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTPointCoveredByAreaBoundary;
                    break;
                case TopoErroType.点要素必须落在面要素内:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTPointProperlyInsideArea;
                    break;
                case TopoErroType.线要素间不能有相互重叠部分:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoOverlap;
                    break;
                case TopoErroType.线要素之间不能相交:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoIntersection;
                    break;
                case TopoErroType.线要素不允许有悬挂点:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoDangles;
                    break;
                case TopoErroType.线要素不允许有假节点:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoPseudos;
                    break;
                case TopoErroType.第一个图层线要素应被第二个线图层线要素覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineCoveredByLineClass;
                    break;
                case TopoErroType.第一个图层线要素不被第二个线图层线要素覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoOverlapLine;
                    break;
                case TopoErroType.点要素应被线要素覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTPointCoveredByLine;
                    break;
                case TopoErroType.点要素应在线要素的端点上:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTPointCoveredByLineEndpoint;
                    break;
                case TopoErroType.面要素边界必须被线要素覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaBoundaryCoveredByLine;
                    break;
                case TopoErroType.面要素的边界必须被另一面要素边界覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaBoundaryCoveredByAreaBoundary;
                    break;
                case TopoErroType.线要素不能自重叠:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoSelfOverlap;
                    break;
                case TopoErroType.线要素不能自相交:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoSelfIntersect;
                    break;
                case TopoErroType.线要素间不能重叠和相交:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoIntersectOrInteriorTouch;
                    break;
                case TopoErroType.线要素端点必须被点要素覆盖:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineEndpointCoveredByPoint;
                    break;
                case TopoErroType.面要素内必须包含至少一个点要素:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAreaContainPoint;
                    break;
                case TopoErroType.线不能是多段:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoMultipart;
                    break;
                case TopoErroType.点要素之间不相交:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTPointDisjoint;
                    break;
                case TopoErroType.线要素必须不相交:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoIntersectLine;
                    break;
                case TopoErroType.线必须不相交或内部接触:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTLineNoIntersectOrInteriorTouchLine;
                    break;
                default:
                    Temp_TopoRuleType = esriTopologyRuleType.esriTRTAny;//将此规则赋予拓扑会直接报错  
                    break;
            }
            return Temp_TopoRuleType;
        }

2.2 根据拓扑关系ID获取拓扑描述

         //根据错误ID获取对应描述  
        public enum TopoErroType
        {
            任何规则 = -1,
            要素大于最小容差 = 0,
            面要素之间无空隙 = 1,
            面要素间无重叠 = 3,
            第二个图层面要素必须被第一个图层任一面要素覆盖 = 4,
            两图层面要素必须互相覆盖 = 5,
            第一个图层面要素必须被第一个图层任一面要素包含 = 7,
            图层间面要素不能相互覆盖 = 8,
            线要素必须跟面图层边界的一部分或全部重叠 = 10,
            线要素必须在面内 = 11,
            点要素必须落在面要素边界上 = 13,
            点要素必须落在面要素内 = 15,
            面要素必须只包含一个点要素 = 16,
            线要素间不能有相互重叠部分 = 19,
            线要素之间不能相交 = 20,
            线要素不允许有悬挂点 = 21,
            线要素不允许有假节点 = 22,
            第一个图层线要素应被第二个线图层线要素覆盖 = 26,
            第一个图层线要素不被第二个线图层线要素覆盖 = 28,
            点要素应被线要素覆盖 = 29,
            点要素应在线要素的端点上 = 31,
            点要素之间不相交 = 34,
            点要素重合点要素 = 35,
            面要素边界必须被线要素覆盖 = 37,
            面要素的边界必须被另一面要素边界覆盖 = 38,
            线要素不能自重叠 = 39,
            线要素不能自相交 = 40,
            线要素间不能重叠和相交 = 41,
            线要素端点必须被点要素覆盖 = 42,
            面要素内必须包含至少一个点要素 = 43,
            线不能是多段 = 44,
            线要素必须不相交 = 45,
            线必须不相交或内部接触 = 46
        };

        /// 
        /// 根据ID获取错误类型
        /// 
        /// l类型ID
        /// 类型字符串
        private string PRV_RecorverTopologyRuleType(int IN_TopoType)
        {
            //根据枚举值获取枚举名  
            string Temp_ErrorDiscripe = Enum.GetName(typeof(TopoErroType), IN_TopoType);
            if (Temp_ErrorDiscripe == null)
                return (IN_TopoType.ToString());//若规则不在列表内则直接返回规则号  
            else
                return Temp_ErrorDiscripe;
        }

X 异常处置

X.1 Error creating topology:-2147220960 Message:应用程序未获得创建或修改此类型数据的方案的许可

X.1.1异常描述

原因:缺乏Advanced许可

基于C#的ArcEngine二次开发22:要素拓扑检查_第5张图片

X.1.2 解决方案

基于C#的ArcEngine二次开发22:要素拓扑检查_第6张图片

只勾选Advanced,其他的不要勾选。

X.2 Error creating topology:-2147220960 Message:尝试打开的数据库已被机器....以排他方式打开

X.2.1 异常描述

这个异常是因为你的数据库文件被其他软件,如ArcGIS打开了,需要关闭

如果要素层同时被ArcGIS打开,会报如下异常:意思是要素已被排他的方式占用

基于C#的ArcEngine二次开发22:要素拓扑检查_第7张图片

X.2.2 解决办法

关闭数据库文件

X.3 从其他地方抄来的关于许可的说明

原文链接:ArcGIS Engine中的License设置

AE开发中的License有两种方法进行设置,一种是通过LicenseControl控件,另一种是通过IAoInitialize接口设置。整个应用程序中只能有一种方式存在,如果进行了两种License设置,就可能产生错误。当然,对于一个健壮的程序而言,我们还需要在初始化之前先判断将被初始化的许可是否可用,应先使用IsProductCodeAvailable方法进行判断,需要初始化扩展模块的许可,可使用CheckOutExtension方法。下面为许可的检测代码

一些重要原则

  1. 初始化许可的一条重要原则就是一个程序只能初始化许可一次,已经初始化许可的程序一旦运行就无法再修改其初始化的许可,即程序运行期间无法修改其使用的许可。
  2. LicenseControl中多选许可是没有意义的,第一个被勾选的许可生效。理论上License中可以勾选多项许可,但运行程序时其作用的是第一个被勾选的许可。如下图只有ArcGIS Engine许可被初始化了。
  3. 什么情况下需要GDB Update许可:当需要对SDE里数据进行编辑时,以及需要在SDE和Personal Geodatabase中创建复杂ArcGIS对象时,需要使用GDB Update许可。对SDE里的数据编辑,很好理解,大致就是进行数据插入,删除,更新;对表添加、删除和修改,表结构的变化(添加、删除列)等,因为这些动作都会造成后台数据库的写操作。
  4. 对 于Personal Geodatabase,进行简单数据对象和编辑,包括创建、删除和修改普通表都是不需要GDB Update许可的,但对于复杂的Geodatabse对象的创建、删除和修改,则需要GDB Update许可,其中复杂的Geodatabse对象包括几何网络,网络分析模型,拓扑,关系类。这也是为什么往往有写好了一个创建几何网络或拓扑的程 序后,执行起来会被报“需要Geodatabase Update许可”的错。
  5. 当需要获取GDB Update许可时,只需勾选ArcGIS Engine Enterprise Geodatabase就可以了

官方参考

  1. Checking for topology error features in a geodatabase topology
  2. ArcEngine 拓扑检查 总结
  3. ArcEngine的拓扑检查类
  4. ArcEngine创建拓扑并验证拓扑

  5. ArcEngine实现拓扑检查


喜欢我的分享,可以关注以下两个公众号:

基于C#的ArcEngine二次开发22:要素拓扑检查_第8张图片

基于C#的ArcEngine二次开发22:要素拓扑检查_第9张图片

你可能感兴趣的:(基于C#的ArcEngine二次开发22:要素拓扑检查)