DayDreamInGIS数据处理工具 V1.1.5_beta 锐角检查工具源码与解析

该博客介绍了如何开发一个GIS插件工具,用于检查多边形要素的锐角。工具核心功能是对多边形的各个节点进行遍历,判断各夹角是否小于给定阈值,尤其关注多部件要素的处理,避免错误的锐角检查。用户界面允许选择图层、设置角度阈值,并提供了检查和取消操作。在检查过程中,工具会创建一个新的结果表,记录不满足条件的锐角信息。此外,博客还展示了界面交互代码和实际的锐角检查算法实现。
摘要由CSDN通过智能技术生成

工具的核心为对多边形要素的各节点进行遍历,分别判断各夹角是否小于给定的阈值。

需要特别注意的是,需考虑多部件要素。由于多部件要素是由多个Ring对象组合而成,若只通过IPointCollection接口拿到点集进行遍历,在多个Ring之间切换时,容易产生错误的锐角检查点,因此,需要对各个Ring对象进行独立的锐角检查。

插件工具界面

 界面源码(WPF)

<Window x:Class="DayDreamInGISTool.CornerCheck.CornerCheckSet"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
            Width="500" Height="270" Title="锐角检查设置" ResizeMode="NoResize">
    <Grid>
        <GroupBox Header="图层" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="64" Width="474">
            <ComboBox HorizontalAlignment="Left" Name="cmbLayer" Height="23" VerticalAlignment="Top" Width="452" Margin="3,10,0,0"/>
        </GroupBox>
        <Label Content="角度阈值(度)" HorizontalAlignment="Left" Margin="10,94,0,0" VerticalAlignment="Top"/>
        <TextBox HorizontalAlignment="Left" Name="txtAngle" Height="23" Margin="88,95,0,0" TextWrapping="Wrap" Text="10" VerticalAlignment="Top" Width="386"/>
        <Label Visibility="Hidden" Content="存储" HorizontalAlignment="Left" Margin="36,144,0,0" VerticalAlignment="Top"/>
        <TextBox Visibility="Hidden" HorizontalAlignment="Left" Name="txtSavePath" Height="23" Margin="88,144,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="319"/>
        <Button Visibility="Hidden" Content="打开" HorizontalAlignment="Left" Name="btnOpen" Margin="419,146,0,0" VerticalAlignment="Top" Width="55" Click="btnOpen_Click"/>
        <Button Content="检查" Name="btnCheck" HorizontalAlignment="Left" Margin="96,193,0,0" VerticalAlignment="Top" Width="75" Height="30" Click="btnCheck_Click"/>
        <Button Content="取消" Name="btnCancel" HorizontalAlignment="Left" Margin="302,193,0,0" VerticalAlignment="Top" Width="75" Height="30" Click="btnCancel_Click"/>

    </Grid>
</Window>

 

界面交互代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Carto;

namespace DayDreamInGISTool.CornerCheck
{
    /// <summary>
    /// CornerCheckSet.xaml 的交互逻辑
    /// </summary>
    public partial class CornerCheckSet : Window
    {
        public CornerCheckSet()
        {
            InitializeComponent();

            GISCommonHelper.CartoLyrHelper.setFeatureLyrCombox(ref cmbLayer, ArcMap.Document.FocusMap, esriGeometryType.esriGeometryPolygon);
        }

        private IFeatureLayer pftlyr = null;
        /// <summary>
        /// 图层
        /// </summary>
        public IFeatureLayer Pftlyr
        {
            get { return pftlyr; }
            set { pftlyr = value; }
        }

        private int angle;
        /// <summary>
        /// 角度阈值
        /// </summary>
        public int Angle
        {
            get { return angle; }
            set { angle = value; }
        }

        private string savepath;
        /// <summary>
        /// 存储路径
        /// </summary>
        public string Savepath
        {
            get { return savepath; }
            set { savepath = value; }
        }

        private void btnOpen_Click(object sender, RoutedEventArgs e)
        {
            string ftcl=GISCommonHelper.GeoDatabaseHelper.Browse4FeatureClass(ArcMap.Application.hWnd);
            txtSavePath.Text = ftcl;
        }

        private void btnCheck_Click(object sender, RoutedEventArgs e)
        {
            if (this.cmbLayer.SelectedIndex == -1)
            {
                MessageBox.Show("未选择图层!");
                return;
            }
            else 
            {
                this.pftlyr = cmbLayer.SelectedValue as IFeatureLayer;
            }

            if (!int.TryParse(txtAngle.Text, out angle))
            {
                MessageBox.Show("角度阈值必须为数值");
                return;
            }

            //if (string.IsNullOrEmpty(txtSavePath.Text))
            //{
            //    MessageBox.Show("未选择保存路径!");
            //    return;
            //}
            //else 
            //{
            //    this.savepath = txtSavePath.Text;
            //}

            this.DialogResult = true;
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }
    }
}

 锐角检查工具代码

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using System.Windows;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Framework;

namespace DayDreamInGISTool.CornerCheck
{
    /// <summary>
    /// 锐角检查
    /// </summary>
    public class btnCornerCheck : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        public btnCornerCheck()
        {
        }

        private IFeatureClass pResultFtCls = null;
        string orignoidfdnm = "Orign_OId";  //源oid
        string corneranglefdnm = "CornerAngle";  //夹角
        string targetanglefdnm = "Angle";  //指向角
        string summaryfdnm = "Summary";  //其他说明

        IStepProgressor stepProgressor = null;
        ITrackCancel trackCancel = null;
        ESRI.ArcGIS.Framework.IProgressDialogFactory progressDialogFactory = new ESRI.ArcGIS.Framework.ProgressDialogFactoryClass();
        IProgressDialog2 progressDialog2;

        protected override void OnClick()
        {
            try
            {
                CornerCheckSet ccs = new CornerCheckSet();
                if (ccs.ShowDialog().Value==true)
                {
                    //进度框
                    trackCancel = new ESRI.ArcGIS.Display.CancelTrackerClass();

                    stepProgressor = progressDialogFactory.Create(trackCancel, ArcMap.Application.hWnd);
                    progressDialog2 = (ESRI.ArcGIS.Framework.IProgressDialog2)stepProgressor;
                    progressDialog2.CancelEnabled = true;
                    progressDialog2.Description = "";
                    progressDialog2.Title = "锐角检查中....";
                    progressDialog2.Animation = ESRI.ArcGIS.Framework.esriProgressAnimationTypes.esriProgressSpiral;
                    progressDialog2.ShowDialog();

                    stepProgressor.MinRange = 0;
                    stepProgressor.MaxRange = ccs.Pftlyr.FeatureClass.FeatureCount(null);
                    stepProgressor.StepValue = 1;

                    //1.创建结果表
                    pResultFtCls = createResultFtCls(ccs);

                    IFeatureCursor pftcursor = ccs.Pftlyr.FeatureClass.Search(null, false);
                    IFeature pFeature = pftcursor.NextFeature();
                    while (pFeature != null)
                    {
                        try
                        {
                            stepProgressor.Message = string.Format("正在检查要素:{0}", pFeature.OID);
                            stepProgressor.Step();
                        }
                        catch
                        {

                        }

                        CornerAngleCheck(pFeature, ccs.Angle);

                        pFeature = pftcursor.NextFeature();
                    }

                    IFeatureLayer pftlyr = new FeatureLayerClass();
                    pftlyr.Name = "锐角检查结果";
                    pftlyr.FeatureClass = pResultFtCls;
                    ArcMap.Document.FocusMap.AddLayer(pftlyr);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发生未知异常:"+ex.Message);
            }
            finally
            {
                trackCancel = null;
                stepProgressor = null;
                if (progressDialog2 != null) 
                {
                    progressDialog2.HideDialog();                    
                }
                progressDialog2 = null;
            }
        }
        
        /// <summary>
        /// 锐角检查
        /// </summary>
        /// <param name="pFeature"></param>
        /// <param name="tolerance"></param>
        private void CornerAngleCheck(IFeature pFeature,int tolerance)
        {
            //多部件要素,分成每个部件单独处理锐角检查
            //以IRing作为单元处理 polygon的内部环是相对于外部环的
            IPolygon4 pPolygon = pFeature.ShapeCopy as IPolygon4;
            IGeometryBag OuterGeometryBag = pPolygon.ExteriorRingBag;

            IGeometryCollection outerGeometryCollection = OuterGeometryBag as IGeometryCollection;
            for (int i = 0; i < outerGeometryCollection.GeometryCount; i++) 
            {
                IGeometry extGeometry = outerGeometryCollection.get_Geometry(i);
                CornerAngleCheck(extGeometry as IRing, tolerance, pFeature.OID);
                //获取内部环集合对象
                IGeometryBag innerGeometryBag = pPolygon.get_InteriorRingBag(extGeometry as IRing);
                IGeometryCollection innterGeometryCollection = innerGeometryBag as IGeometryCollection;

                for (int k = 0; k < innterGeometryCollection.GeometryCount; k++) 
                {
                    IGeometry innerGeometry = innterGeometryCollection.get_Geometry(k);
                    CornerAngleCheck(innerGeometry as IRing, tolerance, pFeature.OID);
                }
            }
        }

        /// <summary>
        /// 锐角检查
        /// </summary>
        /// <param name="pPolygon"></param>
        /// <param name="tolerance"></param>
        /// <param name="oid">源要素OId</param>
        private void CornerAngleCheck(IRing pPolygon, int tolerance, int oid)
        {
            IPointCollection pntCol = pPolygon as IPointCollection;
            for (int i = 0; i < pntCol.PointCount - 1; i++)  //循环,多边形的点首位相接,最后一个点不用核查
            {
                stepProgressor.Message = string.Format("正在检查要素{0}第{1}个节点", oid, i.ToString());
                IPoint currentpnt = pntCol.Point[i];
                IPoint prePoint = null;
                IPoint nextPoint = null;
                if (i == 0)
                {
                    prePoint = pntCol.Point[pntCol.PointCount - 2];  //获取倒数第二个点,即为肉眼意义上的前一个点
                }
                else
                {
                    prePoint = pntCol.Point[i - 1];
                }

                if (i == pntCol.PointCount - 2)
                {
                    nextPoint = pntCol.Point[0];
                }
                else
                {
                    nextPoint = pntCol.Point[i + 1];
                }

                double ca = calcCornerAngle(currentpnt, prePoint, nextPoint);
                double aindegredd = GISCommonHelper.MathHelper.Radian2Degree(ca);
                double d1 = GISCommonHelper.GeometryHelper.getDistance(currentpnt, prePoint);
                double d2 = GISCommonHelper.GeometryHelper.getDistance(currentpnt, nextPoint);

                //生成定位点
                IConstructPoint pc = new PointClass();
                //定位点距离大致算
                double dis = (d1 + d2) / 5.0;  //平均边长的十分之一处
                pc.ConstructAngleDistance(currentpnt, GISCommonHelper.GeometryHelper.getAngle(currentpnt, prePoint) + ca / 2.0, dis);

                if (aindegredd <= tolerance)
                {
                    //锐角
                    IFeature newFeature = pResultFtCls.CreateFeature();
                    newFeature.set_Value(newFeature.Fields.FindField(orignoidfdnm), oid);  //源图斑OId
                    newFeature.set_Value(newFeature.Fields.FindField(corneranglefdnm), aindegredd); //夹角
                    //newFeature.set_Value(newFeature.Fields.FindField(targetanglefdnm), 0);  //指向角度
                    //newFeature.Shape = pc as IPoint;
                    IPolyline pPolyline = GISCommonHelper.GeometryHelper.getPolyline(pc as IPoint, currentpnt);
                    newFeature.Shape = pPolyline;
                    newFeature.Store();
                    //newFeature.set_Value(newFeature.Fields.FindField(summaryfdnm), "--");  //说明字段
                }
                else
                {
                    //非锐角
                }
            }
        }

        /// <summary>
        /// 计算夹角 返回结果弧度
        /// </summary>
        /// <param name="cPnt">顶点</param>
        /// <param name="p1">起点</param>
        /// <param name="p2">结点</param>
        /// <returns>弧度</returns>
        public double calcCornerAngle(IPoint cPnt,IPoint p1,IPoint p2)
        {
            double a1 = GISCommonHelper.GeometryHelper.getAngle(cPnt, p1);
            double a2 = GISCommonHelper.GeometryHelper.getAngle(cPnt, p2);
            double a = a2 - a1;
            if (a < 0)
            {
                a = a + Math.PI * 2;
            }

            return a;
        }

        /// <summary>
        /// 创建结果表
        /// </summary>
        /// <param name="ccs"></param>
        private IFeatureClass createResultFtCls(CornerCheckSet ccs)
        {
            ISpatialReference psr=((IGeoDataset)ccs.Pftlyr.FeatureClass).SpatialReference;

            IWorkspace pws = GISCommonHelper.GeoDatabaseHelper.CreateInMemoryWorkspace();
            IFeatureWorkspace pfws = pws as IFeatureWorkspace;
            //配置字段
            IFieldsEdit fdsedit = new FieldsClass();

            //来源要素OId
            IFieldEdit fe = new FieldClass();
            fe.Name_2 = orignoidfdnm;
            fe.Type_2 = esriFieldType.esriFieldTypeInteger;
            fe.AliasName_2 = "来源要素OId";
            fdsedit.AddField(fe as IField);

            //夹角
            fe = new FieldClass();
            fe.Name_2 = corneranglefdnm;
            fe.Type_2 = esriFieldType.esriFieldTypeDouble;
            fe.AliasName_2 = "夹角";
            fdsedit.AddField(fe as IField);

            //指向角度
            fe = new FieldClass();
            fe.Name_2 = targetanglefdnm;
            fe.Type_2 = esriFieldType.esriFieldTypeDouble;
            fe.AliasName_2 = "指向角度";
            fdsedit.AddField(fe as IField);

            //其他说明
            fe = new FieldClass();
            fe.Name_2 = summaryfdnm;
            fe.Type_2 = esriFieldType.esriFieldTypeString;
            fe.Length_2 = 50;
            fe.AliasName_2 = "说明";
            fdsedit.AddField(fe as IField);

            IGeometryDefEdit pGeoDef = new GeometryDefClass();
            //pGeoDef.GeometryType_2 = esriGeometryType.esriGeometryPoint;
            pGeoDef.GeometryType_2 = esriGeometryType.esriGeometryPolyline;
            //设置空间参考
            pGeoDef.SpatialReference_2 = psr;

            fe = new FieldClass();
            fe.Type_2 = esriFieldType.esriFieldTypeGeometry;
            fe.GeometryDef_2 = pGeoDef;
            fe.Name_2 = "shape";
            fdsedit.AddField(fe);

            //字段验证
            IFieldChecker fieldChecker = new FieldCheckerClass();
            IEnumFieldError enumFieldError = null;
            IFields validatedFields = null;
            fieldChecker.ValidateWorkspace = pws;
            fieldChecker.Validate(fdsedit as IFields, out enumFieldError, out validatedFields);

            //创建结果点集
            return pfws.CreateFeatureClass(System.IO.Path.GetRandomFileName(), fdsedit as IFields,null,null,esriFeatureType.esriFTSimple,"shape","");
        }

        protected override void OnUpdate()
        {
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值