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;
            }

        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/451769.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】qsort函数的使用

1.使用qsort函数排序整型数据 #include <stdio.h> #include <string.h> #include <stdlib.h>//void qsort(void* base, //指针&#xff0c;指向的是待排序的数组的第一个元素 // size_t num, //是base指向的待排序数组的元素个数 // siz…

力扣每日一题 在受污染的二叉树中查找元素 哈希 DFS 二进制

Problem: 1261. 在受污染的二叉树中查找元素 思路 &#x1f468;‍&#x1f3eb; 灵神题解 &#x1f496; 二进制 时间复杂度&#xff1a;初始化为 O ( 1 ) O(1) O(1)&#xff1b;find 为 O ( m i n ( h , l o g 2 t a r g e t ) O(min(h,log_2target) O(min(h,log2​targ…

Django 学习笔记(Day1)

「写在前面」 本文为千锋教育 Django 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。 目录 0 课程介绍 1 Django 快速入门 1.1 Django 介绍 1.2 Django 安装 1.3 创建 Django 项目 1.4 运行 Django 项目 1.5 数据迁…

【C#】.net core 6.0 使用第三方日志插件Log4net,日志输出到控制台或者文本文档

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

【C++】stack/queue

链表完了之后就是我们的栈和队列了&#xff0c;当然我们的STL中也有实现&#xff0c;下面我们先来看一下简单用法&#xff0c;跟我们之前C语言实现的一样&#xff0c;stack和queue有这么几个重要的成员函数 最主要的就是这么几个&#xff1a;empty&#xff0c;push&#xff0c;…

python读取大型csv文件,降低内存占用,提高程序处理速度

文章目录 简介读取前多少行读取属性列逐块读取整个文件总结参考资料 简介 遇到大型的csv文件时&#xff0c;pandas会把该文件全部加载进内存&#xff0c;从而导致程序运行速度变慢。 本文提供了批量读取csv文件、读取属性列的方法&#xff0c;减轻内存占用情况。 import pand…

git commit --amend

git commit --amend 1. 修改已经输入的commit 1. 修改已经输入的commit 我已经输入了commit fix: 删除无用代码 然后现在表示不准确&#xff0c;然后我通过命令git commit --amend修改commit

鼓楼夜市管理wpf+sqlserver

鼓楼夜市管理系统wpfsqlserver 下载地址:鼓楼夜市管理系统wpfsqlserver 说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于C#wpf架构和sql server数据库 功能模块&#xff1a; 登录注册 鼓楼夜市管理系统主界面所有店铺信…

企业电子招投标系统源码-从源码到实践:深入了解鸿鹄电子招投标系统与电子招投标

在数字化采购领域&#xff0c;企业需要一个高效、透明和规范的管理系统。通过采用Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;我们打造了全过程数字化采购管理平台。该平台具备内外协同的能力&#xff0c;通过待办消息、招标公告、中标公告和信息发布等功能模块…

Tictoc3例子

在tictoc3中&#xff0c;实现了让 tic 和 toc 这两个简单模块之间传递消息&#xff0c;传递十次后结束仿真。 首先来介绍一下程序中用到的两个函数&#xff1a; 1.omnetpp中获取模块名称的函数 virtual const char *getName() const override {return name ? name : "&q…

Python 一步一步教你用pyglet制作汉诺塔游戏(终篇)

目录 汉诺塔游戏 完整游戏 后期展望 汉诺塔游戏 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;是一个源于印度古老传说的益智玩具。这个传说讲述了大梵天创造世界的时候&#xff0c;他做了三根金刚石柱子&#xff0c;并在其中一根柱子上从下往上按照大小顺序摞…

js【详解】Promise

为什么需要使用 Promise &#xff1f; 传统回调函数的代码层层嵌套&#xff0c;形成回调地狱&#xff0c;难以阅读和维护&#xff0c;为了解决回调地狱的问题&#xff0c;诞生了 Promise 什么是 Promise &#xff1f; Promise 是一种异步编程的解决方案&#xff0c;本身是一个构…

套接字的地址结构,IP地址转换函数,网络编程的接口

目录 一、套接字的地址结构 1.1 通用socket地址结构 1.2 专用socket地址结构 1.2.1 tcp协议族 1.2.3 IP协议族 二、IP地址转换函数 三、网络编程接口 3.1 socket() 3.2 bind() 3.3 listen() 3.4 accept() 3.5 connect() 3.6 close() 3.7 recv()、send() 3.8 recv…

手写简易操作系统(五)--获得物理内存容量

前情提要 上一章中我们进入了保护模式&#xff0c;并且跳转到了32位模式下执行。这一章较为简单&#xff0c;我们来获取物理内存的实际容量。 一、获得内存容量的方式 在Linux中有多种方法获取内存容量&#xff0c;如果一种方法失败&#xff0c;就会试用其他方法。其本质上是…

考研数学|汤家凤《1800》vs 张宇《1000》,怎么选?

汤家凤的1800题和张宇的1000题都是备考数学考研的热门选择&#xff0c;但究竟哪个更适合备考呢&#xff1f;下面分享一些见解。 首先&#xff0c;让我们来看看传统习题册存在的一些问题。虽然传统习题册通常会覆盖考试的各个知识点和题型&#xff0c;但其中一些问题在于它们可…

JDBC连接MysqL

import java.sql.*;public class Demo {public static void main(String[] args) throws ClassNotFoundException, SQLException {//1.注册驱动&#xff0c;加载驱动&#xff1b;Class.forName("com.mysql.jdbc.Driver");//2.获得连接,返回connection类型的对象&…

汤唯短发造型:保留经典和适合自己的风格,也许才是最重要的

汤唯短发造型&#xff1a;保留经典和适合自己的风格&#xff0c;也许才是最重要的 汤唯短发造型登上Vogue四月刊封面&#xff0c;引发网友热议。#李秘书讲写作#说说是怎么回事&#xff1f; 这次Vogue四月刊的封面大片&#xff0c;汤唯以一头短发亮相&#xff0c;身穿五颜六色的…

钉钉平台“智”领宠物界,开启萌宠智能新时代!

在当前数字化转型的浪潮中&#xff0c;钉钉用便捷的数字化解决方案推动了宠物业界的智能升级。一家宠物用品公司采用无雀科技数字化管理系统&#xff0c;与钉钉平台结合&#xff0c;解决了小型企业普遍存在的财务管理不清晰、业务流程不规范、客户信息核对繁琐等痛点问题。 针对…

一周学会Django5 Python Web开发-Django5内置模板引擎-模板继承

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计34条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Linux中文件的权限

我们首先需要明白&#xff0c;权限 用户角色 文件的权限属性 一、拥有者、所属组和other&#xff08;用户角色&#xff09; 以文件file1为例 第一个箭头所指处即是文件的拥有者&#xff0c;拥有者为zz 第二个箭头所指处即使文件的所属组&#xff0c;所属组为zz 除去拥有者…