DayDreamInGIS 之 ArcGIS Pro二次开发 锐角检查

功能:检查图斑中所有的夹角,如果为锐角,在单独的标记图层中标记。生成的结果放在默认gdb中,以 图层名_锐角检查 的方式命名

大体实现方式:遍历图层中的所有要素(多部件要素分别处理),对每个夹角进行判断。

具体功能与ArcMap中锐角检查工具类似

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

工具界面:

(使用prowindow,样式确实更和谐)

界面代码:

<controls:ProWindow x:Class="DayDreamInGISTool.CornerCheck.CornerCheckWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:controls="clr-namespace:ArcGIS.Desktop.Framework.Controls;assembly=ArcGIS.Desktop.Framework"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:extensions="clr-namespace:ArcGIS.Desktop.Extensions;assembly=ArcGIS.Desktop.Extensions"
        mc:Ignorable="d"
        Title="锐角检查" Width="500" Height="200" 
        WindowStartupLocation="CenterOwner"
    >
    <controls:ProWindow.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <extensions:DesignOnlyResourceDictionary Source="pack://application:,,,/ArcGIS.Desktop.Framework;component\Themes\Default.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </controls:ProWindow.Resources>
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="90"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label VerticalAlignment="Center" HorizontalAlignment="Right">图层</Label>
            <ComboBox Grid.Column="1" Name="cmbLayer" VerticalAlignment="Center" Height="27"></ComboBox>
        </Grid>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="90"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label VerticalAlignment="Center" HorizontalAlignment="Right">角度阈值(度)</Label>
            <TextBox Grid.Column="1" Name="txtYuzhi" VerticalAlignment="Center" Height="27" Text="10"></TextBox>
        </Grid>
        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Button Width="140" Height="35" Name="btnOK" Click="btnOK_Click">确定</Button>
            <Button Width="140" Height="35" Grid.Column="1" Name="btnCancel" Click="btnCancel_Click">取消</Button>
        </Grid>
    </Grid>
</controls:ProWindow>

界面交互代码:

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 ArcGIS.Core.Data;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using RGeometry=ArcGIS.Core.Geometry;
using GISCommonHelper;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Core;
using ArcGIS.Core.Data.DDL;
using ArcGIS.Desktop.Editing;
using ArcGIS.Core.Data.Exceptions;
using ArcGIS.Core.Internal.CIM;

namespace DayDreamInGISTool.CornerCheck
{
    /// <summary>
    /// Interaction logic for CornerCheckWindow.xaml
    /// </summary>
    public partial class CornerCheckWindow : ArcGIS.Desktop.Framework.Controls.ProWindow
    {
        private FeatureLayer player;

        private double yuzhi;

        public CornerCheckWindow()
        {
            InitializeComponent();
            try
            {
                var map = MapView.Active.Map;
                cmbLayer.setLyrlist<FeatureLayer>(map, (o, e) =>
                {
                    if (cmbLayer.SelectedIndex != -1)
                    {
                        Player = this.cmbLayer.SelectedValue as FeatureLayer;
                    }
                });
            }
            catch (Exception)
            {

                
            }
            
        }

        public FeatureLayer Player { get => player; set => player = value; }
        public double Yuzhi { get => yuzhi; set => yuzhi = value; }

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

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            if (this.cmbLayer.SelectedIndex == -1)
            {
                MessageBox.Show("请设置图层");
                return;
            }

            if(double.TryParse(txtYuzhi.Text,out yuzhi))
            {

            }
            else
            {
                MessageBox.Show("阈值必须为数字");
                return;
            }

            this.DialogResult = true;
        }
    }
}

核心逻辑代码,放在ProWindow的showButton中。

using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Data.DDL;
using ArcGIS.Core.Data.Exceptions;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Catalog;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Extensions;
using ArcGIS.Desktop.Framework;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Layouts;
using ArcGIS.Desktop.Mapping;
using GISCommonHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace DayDreamInGISTool.CornerCheck
{
    internal class ShowCornerCheckWindow : Button
    {

        private CornerCheckWindow _cornercheckwindow = null;

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

        private FeatureLayer pftlyr;
        private double yuzhi;

        ProgressDialog progDlg = null;
        CancelableProgressorSource progSrc = null;

        protected override void OnClick()
        {
            //already open?
            if (_cornercheckwindow != null)
                return;
            _cornercheckwindow = new CornerCheckWindow();
            _cornercheckwindow.Owner = FrameworkApplication.Current.MainWindow;
            //_cornercheckwindow.Closed += (o, e) => { _cornercheckwindow = null; };
            //_cornercheckwindow.Show();
            //uncomment for modal
            try
            {
                progDlg = new ProgressDialog($"锐角检查中...", "取消", 100, true);

                bool? res = _cornercheckwindow.ShowDialog();
                if (res.Value)
                {
                    yuzhi = _cornercheckwindow.Yuzhi;
                    pftlyr = _cornercheckwindow.Player;
                    //{pftlyr.GetDefinition().Name} 
                    progDlg.Show();
                    
                    progSrc = new CancelableProgressorSource(progDlg);
                    execute();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发生未知异常_"+ex.Message);
                
            }
            finally
            {
                if (progDlg != null)
                {
                    progDlg.Hide();
                    progDlg.Dispose();
                }
                _cornercheckwindow = null;
            }
        }

        private void execute()
        {
            //暂时不做进度条
            QueuedTask.Run(() =>
            {
                long ftcount=pftlyr.GetFeatureClass().GetCount();
                progSrc.Progressor.Max = (uint)ftcount;

                resultFtCls = createResultFtCls();

                FeatureClass ftcls = pftlyr.GetFeatureClass();
                using (RowCursor cursor = ftcls.Search())
                {
                    EditOperation editOperation = new EditOperation();

                    while (cursor.MoveNext())
                    {
                        using (Feature feature = cursor.Current as Feature)
                        {
                            long oid = feature.GetObjectID();
                            Geometry geo = feature.GetShape();
                            if (geo.GeometryType == ArcGIS.Core.Geometry.GeometryType.Polygon)
                            {
                                var polygon = geo as Polygon;
                                check(polygon, oid, editOperation);
                            }
                            progSrc.Progressor.Value++;
                            progSrc.Message = $"要素:{oid} 检查完成";
                        }
                    }
                    string message = "";

                    try
                    {
                        // 执行编辑操作
                        bool creationResult = editOperation.Execute();
                        
                        // 如果操作失败,存储错误消息
                        if (!creationResult) { message = editOperation.ErrorMessage; }
                    }
                    catch (GeodatabaseException exObj)
                    {
                        // 如果出现地理数据库异常,存储异常消息
                        message = exObj.Message;
                        throw;
                    }
                }

            },progSrc.Progressor);
        }

        private void check(Polygon polygon, long oid, EditOperation editOperation)
        {
            //多部件要素,每个部分单独处理
            var list = GeometryEngine.Instance.MultipartToSinglePart(polygon);
            foreach (var item in list)
            {
                CornerAngleCheck(item as Polygon, yuzhi, oid, editOperation);
            }
        }

        private void CornerAngleCheck(Polygon pPolygon, double tolerance, long oid, EditOperation editOperation)
        {
            var pntCol = pPolygon.Points;
            for (int i = 0; i < pntCol.Count - 1; i++)  //循环,多边形的点首尾相接,最后一个点不用核查
            {
                MapPoint currentpnt = pntCol[i];
                MapPoint prePoint = null;
                MapPoint nextPoint = null;
                if (i == 0)
                {
                    prePoint = pntCol[pntCol.Count - 2];  //获取倒数第二个点,即为肉眼意义上的前一个点
                }
                else
                {
                    prePoint = pntCol[i - 1];
                }

                if (i == pntCol.Count - 2)
                {
                    nextPoint = pntCol[0];
                }
                else
                {
                    nextPoint = pntCol[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);

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

                if (aindegredd <= tolerance)
                {
                    editOperation.Callback(context => {
                        using RowBuffer rowBuffer = resultFtCls.CreateRowBuffer();
                        rowBuffer[orignoidfdnm] = oid;
                        rowBuffer[corneranglefdnm] = aindegredd;
                        //rowBuffer[targetanglefdnm] = 0;  //指向角度
                        //构建线
                        Polyline pln = GISCommonHelper.GeometryHelper.getPolyline(pc, currentpnt, MapView.Active.Map.SpatialReference);
                        rowBuffer[resultFtCls.GetDefinition().GetShapeField()] = pln;

                        using Feature feature = resultFtCls.CreateRow(rowBuffer);
                        context.Invalidate(feature);
                    }, resultFtCls);
                }
                else
                {
                    //非锐角
                }
            }
        }

        /// <summary>
        /// 计算夹角 返回结果弧度
        /// </summary>
        /// <param name="cPnt">顶点</param>
        /// <param name="p1">起点</param>
        /// <param name="p2">结点</param>
        /// <returns>弧度</returns>
        public double calcCornerAngle(MapPoint cPnt, MapPoint p1, MapPoint 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;
        }

        string ruijiaojcfcname = "锐角检查";

        /// <summary>
        /// 创建结果要素类 默认
        /// </summary>
        /// <returns></returns>
        private FeatureClass createResultFtCls()
        {
            ruijiaojcfcname = $"{pftlyr.GetDefinition().Name}_锐角检查";
            var sr = pftlyr.GetFeatureClass().GetDefinition().GetSpatialReference();
            //在当前数据库中创建
            var DefaultGDB = Project.Current.DefaultGeodatabasePath;
            using (Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(DefaultGDB))))
            {
                bool isexist = gdb.FeatureClassExists(ruijiaojcfcname);
                //如果存在,则先删除
                if (isexist)
                {
                    var dr=MessageBox.Show("工作空间已经存在锐角检查数据集,是否删除?", "提示", System.Windows.MessageBoxButton.YesNo);

                    if(dr== System.Windows.MessageBoxResult.Yes)
                    {
                        //删除已有
                        var featureclass = gdb.OpenDataset<FeatureClass>(ruijiaojcfcname);
                        FeatureClassDescription fdc = new FeatureClassDescription(featureclass.GetDefinition());
                        SchemaBuilder sb3 = new SchemaBuilder(gdb);
                        sb3.Delete(fdc);
                    }
                    else
                    {
                        ruijiaojcfcname = $"锐角检查_{DateTime.Now.GetTimeStamp()}";
                    }
                    progSrc.Progressor.Message = $"创建结果数据集 {ruijiaojcfcname} 完成";
                }

                var hasZ = false;
                var hasM = false;
                var shapeDescription = new ShapeDescription(GeometryType.Polyline, sr)
                {
                    HasM = hasM,
                    HasZ = hasZ
                };
                var f0 = new ArcGIS.Core.Data.DDL.FieldDescription("OBJECTID", FieldType.OID);
                var f1 = new ArcGIS.Core.Data.DDL.FieldDescription(orignoidfdnm, FieldType.Integer);
                var f2 = new ArcGIS.Core.Data.DDL.FieldDescription(corneranglefdnm, FieldType.Double);
                var f3 = new ArcGIS.Core.Data.DDL.FieldDescription(targetanglefdnm, FieldType.Double);
                var f4 = new ArcGIS.Core.Data.DDL.FieldDescription(summaryfdnm, FieldType.String);
                f4.Length = 80;
                var fieldDescriptions = new List<ArcGIS.Core.Data.DDL.FieldDescription>()
                {
                    f0,f1,f2,f3,f4
                };

                //创建FeatureClassDescription
                var fcDescription = new FeatureClassDescription(ruijiaojcfcname, fieldDescriptions, shapeDescription);
                //创建SchemaBuilder
                SchemaBuilder sb = new SchemaBuilder(gdb);
                sb.Create(fcDescription);
                bool success = sb.Build();
                var featureclass2 = gdb.OpenDataset<FeatureClass>(ruijiaojcfcname); ;  //再次打开

                //添加图层
                Uri uu = featureclass2.GetPath();
                var layer = LayerFactory.Instance.CreateLayer(uu, MapView.Active.Map, 0, ruijiaojcfcname);

                return featureclass2;
            }

        }
    }
}

相关推荐

  1. Superset开发Superset Organizations

    2024-03-13 06:46:04       43 阅读
  2. Superset开发 配置Docker

    2024-03-13 06:46:04       41 阅读
  3. Superset开发环境部署(Docker版)

    2024-03-13 06:46:04       62 阅读
  4. Superset开发Superset架构理解

    2024-03-13 06:46:04       40 阅读
  5. Superset开发PostgreSQL 统计信息介绍

    2024-03-13 06:46:04       43 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-13 06:46:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-13 06:46:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-13 06:46:04       82 阅读
  4. Python语言-面向对象

    2024-03-13 06:46:04       91 阅读

热门阅读

  1. 使用动态ip上网稳定吗?

    2024-03-13 06:46:04       43 阅读
  2. Django调用mysql

    2024-03-13 06:46:04       40 阅读
  3. 深入解析 Go 语言中的 http.FileSystem

    2024-03-13 06:46:04       29 阅读
  4. HarmonyOS ArkTS HTTP 请求简单封装(二十二)

    2024-03-13 06:46:04       38 阅读
  5. 智慧城市数据大融合的几点想法

    2024-03-13 06:46:04       39 阅读
  6. 突破编程_C++_设计模式(命令模式)

    2024-03-13 06:46:04       35 阅读
  7. 命令模式在量化交易系统开发中的应用

    2024-03-13 06:46:04       46 阅读
  8. golang将pcm格式音频转为mp3格式

    2024-03-13 06:46:04       37 阅读