功能:检查图斑中所有的夹角,如果为锐角,在单独的标记图层中标记。生成的结果放在默认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;
}
}
}
}