前面一篇博客介绍了如何按距离或按比例将1
条线段分成2
条线段的方法,核心就是利用IFeatureEdit
接口的Split
方法进行分割。但就像之前说的,该方法只适用于将1
条线段分成2
条线段,如果我们希望将1
条线段分成n
条线段(n >= 2)
,那又该怎么做呢?下面开始介绍。
假设有一条长度为100米
的线段,现在按照30米
的距离间隔对其进行分割,那么就会得到如下图所示的结果,线段被A、B、C
三个分割点分成了4
份,
现在第一个问题来了:如何获取这些分割点
?其实这个问题很简单,在IPolyline
接口中有一个QueryPoint
方法,该方法可以在指定的距离处获取线上的一点,我们可以来测试一下:
获取分割点代码
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.ADF.CATIDs; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.Display; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace WindowsFormsApplication1.Command { /// <summary> /// Summary description for SplitByDistanceCommand. /// </summary> [Guid("b8a71064-25d0-4816-9b9a-0f3738ddf981")] [ClassInterface(ClassInterfaceType.None)] [ProgId("WindowsFormsApplication1.Command.SplitByDistanceCommand")] public sealed class SplitByDistanceCommand : BaseCommand { #region COM Registration Function(s) [ComRegisterFunction()] [ComVisible(false)] static void RegisterFunction(Type registerType) { // Required for ArcGIS Component Category Registrar support ArcGISCategoryRegistration(registerType); // // TODO: Add any COM registration code here // } [ComUnregisterFunction()] [ComVisible(false)] static void UnregisterFunction(Type registerType) { // Required for ArcGIS Component Category Registrar support ArcGISCategoryUnregistration(registerType); // // TODO: Add any COM unregistration code here // } #region ArcGIS Component Category Registrar generated code /// <summary> /// Required method for ArcGIS Component Category registration - /// Do not modify the contents of this method with the code editor. /// </summary> private static void ArcGISCategoryRegistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); ControlsCommands.Register(regKey); } /// <summary> /// Required method for ArcGIS Component Category unregistration - /// Do not modify the contents of this method with the code editor. /// </summary> private static void ArcGISCategoryUnregistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); ControlsCommands.Unregister(regKey); } #endregion #endregion private IHookHelper m_hookHelper; public SplitByDistanceCommand() { // // TODO: Define values for the public properties // base.m_category = ""; //localizable text base.m_caption = ""; //localizable text base.m_message = ""; //localizable text base.m_toolTip = ""; //localizable text base.m_name = ""; //unique id, non-localizable (e.g. "MyCategory_MyCommand") try { // // TODO: change bitmap name if necessary // string bitmapResourceName = GetType().Name + ".bmp"; base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap"); } } #region Overridden Class Methods /// <summary> /// Occurs when this command is created /// </summary> /// <param name="hook">Instance of the application</param> public override void OnCreate(object hook) { if (hook == null) return; if (m_hookHelper == null) m_hookHelper = new HookHelperClass(); m_hookHelper.Hook = hook; // TODO: Add other initialization code } /// <summary> /// Occurs when this command is clicked /// </summary> public override void OnClick() { if (m_hookHelper.FocusMap.SelectionCount != 1) { MessageBox.Show("请选择1条线要素进行分割", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 获取被选择的要素 IEnumFeature pEnumFeature = m_hookHelper.FocusMap.FeatureSelection as IEnumFeature; pEnumFeature.Reset(); IFeature pFeature = pEnumFeature.Next(); if (pFeature.Shape is IPoint || pFeature.Shape is IPolygon) { MessageBox.Show("请选择1条线要素进行分割", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 获取分割点 IPolyline pPolyline = pFeature.ShapeCopy as IPolyline; List<IPoint> points = new List<IPoint>(); double distance = 50; double interval = 50; while (distance < pPolyline.Length) { IPoint pPoint = new ESRI.ArcGIS.Geometry.Point(); pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, distance, false, pPoint); points.Add(pPoint); distance += interval; } // 创建颜色 IRgbColor pRgbColor = new RgbColor(); pRgbColor.Red = 255; pRgbColor.Green = 0; pRgbColor.Blue = 0; // 创建点符号 ISimpleMarkerSymbol pSimpleMarkerSymbol = new SimpleMarkerSymbol(); pSimpleMarkerSymbol.Color = pRgbColor; pSimpleMarkerSymbol.Size = 15; pSimpleMarkerSymbol.Style = esriSimpleMarkerStyle.esriSMSCircle; // 绘制分割点 foreach (IPoint pPoint in points) { IMarkerElement pMarkerElement = new MarkerElement() as IMarkerElement; pMarkerElement.Symbol = pSimpleMarkerSymbol; IElement pElement = pMarkerElement as IElement; pElement.Geometry = pPoint; m_hookHelper.ActiveView.GraphicsContainer.AddElement(pElement, 0); } // 刷新地图 m_hookHelper.ActiveView.Refresh(); } #endregion } }
运行结果如下图所示,可以发现:这条线段长度为164米
,按照50米
的距离间隔对其进行分割,结果在50米、100米、150米
处产生了3个
分割点。
现在需要思考一下:分割操作的结束条件是什么
?还是上面的情景,我们来模拟一下:
164米
的线段,在50米
处执行分割操作,得到50米
和114米
两条线段114米
的线段,在50米
处执行分割操作,得到50米
和64
米两条线段64米
的线段,在50米
处执行分割操作,得到50米
和14
米两条线段50米
和14米
这两条线段的长度均小于等于50米
,因此不再执行分割操作。通过上面的分析可以得出结论:
每次分割的对象都是距离较长的那条线段
当执行分割操作后的两条线段长度均小于等于指定的距离间隔时,分割结束
4.1、主界面代码
using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.SystemUI; using System; using System.Windows.Forms; using WindowsFormsApplication1.Command; namespace WindowsFormsApplication1 { public partial class MainForm : Form { public MainForm() { InitializeComponent(); axMapControl1.LoadMxFile(@"C:\Users\DSF\Desktop\data\无标题.mxd"); axMapControl1.Extent = axMapControl1.FullExtent; btnStartEditing.Enabled = true; btnStopEditing.Enabled = false; btnSelect.Enabled = false; btnSplitByDistance.Enabled = false; btnSplitByRatio.Enabled = false; } // 开始编辑 private void btnStartEditing_Click(object sender, EventArgs e) { ICommand command = new ControlsEditingStartCommand(); command.OnCreate(axMapControl1.Object); command.OnClick(); btnStartEditing.Enabled = false; btnStopEditing.Enabled = true; btnSelect.Enabled = true; btnSplitByDistance.Enabled = true; btnSplitByRatio.Enabled = true; } // 结束编辑 private void btnStopEditing_Click(object sender, EventArgs e) { ICommand saveCommand = new ControlsEditingSaveCommand(); saveCommand.OnCreate(axMapControl1.Object); saveCommand.OnClick(); ICommand clearSelectionCommand = new ControlsClearSelectionCommand(); clearSelectionCommand.OnCreate(axMapControl1.Object); clearSelectionCommand.OnClick(); btnStartEditing.Enabled = true; btnStopEditing.Enabled = false; btnSelect.Enabled = false; btnSplitByDistance.Enabled = false; btnSplitByRatio.Enabled = false; } // 选择要素 private void btnSelect_Click(object sender, EventArgs e) { ICommand command = new ControlsSelectFeaturesTool(); command.OnCreate(axMapControl1.Object); axMapControl1.CurrentTool = command as ITool; } // 距离分割 private void btnSplitByDistance_Click(object sender, EventArgs e) { ICommand command = new SplitByDistanceCommand(); command.OnCreate(axMapControl1.Object); command.OnClick(); } // 比例分割 private void btnSplitByRatio_Click(object sender, EventArgs e) { ICommand command = new SplitByRatioCommand(); command.OnCreate(axMapControl1.Object); command.OnClick(); } } }
4.2、距离分割代码
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.ADF.CATIDs; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace WindowsFormsApplication1.Command { /// <summary> /// Summary description for SplitByDistanceCommand. /// </summary> [Guid("b8a71064-25d0-4816-9b9a-0f3738ddf981")] [ClassInterface(ClassInterfaceType.None)] [ProgId("WindowsFormsApplication1.Command.SplitByDistanceCommand")] public sealed class SplitByDistanceCommand : BaseCommand { #region COM Registration Function(s) [ComRegisterFunction()] [ComVisible(false)] static void RegisterFunction(Type registerType) { // Required for ArcGIS Component Category Registrar support ArcGISCategoryRegistration(registerType); // // TODO: Add any COM registration code here // } [ComUnregisterFunction()] [ComVisible(false)] static void UnregisterFunction(Type registerType) { // Required for ArcGIS Component Category Registrar support ArcGISCategoryUnregistration(registerType); // // TODO: Add any COM unregistration code here // } #region ArcGIS Component Category Registrar generated code /// <summary> /// Required method for ArcGIS Component Category registration - /// Do not modify the contents of this method with the code editor. /// </summary> private static void ArcGISCategoryRegistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); ControlsCommands.Register(regKey); } /// <summary> /// Required method for ArcGIS Component Category unregistration - /// Do not modify the contents of this method with the code editor. /// </summary> private static void ArcGISCategoryUnregistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); ControlsCommands.Unregister(regKey); } #endregion #endregion private IHookHelper m_hookHelper; public SplitByDistanceCommand() { // // TODO: Define values for the public properties // base.m_category = ""; //localizable text base.m_caption = ""; //localizable text base.m_message = ""; //localizable text base.m_toolTip = ""; //localizable text base.m_name = ""; //unique id, non-localizable (e.g. "MyCategory_MyCommand") try { // // TODO: change bitmap name if necessary // string bitmapResourceName = GetType().Name + ".bmp"; base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap"); } } #region Overridden Class Methods /// <summary> /// Occurs when this command is created /// </summary> /// <param name="hook">Instance of the application</param> public override void OnCreate(object hook) { if (hook == null) return; if (m_hookHelper == null) m_hookHelper = new HookHelperClass(); m_hookHelper.Hook = hook; // TODO: Add other initialization code } /// <summary> /// Occurs when this command is clicked /// </summary> public override void OnClick() { if (m_hookHelper.FocusMap.SelectionCount != 1) { MessageBox.Show("请选择1条线要素进行分割", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 获取被选择的要素 IEnumFeature pEnumFeature = m_hookHelper.FocusMap.FeatureSelection as IEnumFeature; pEnumFeature.Reset(); IFeature pFeature = pEnumFeature.Next(); if (pFeature.Shape is IPoint || pFeature.Shape is IPolygon) { MessageBox.Show("请选择1条线要素进行分割", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 获取分割点 IPolyline pPolyline = pFeature.ShapeCopy as IPolyline; List<IPoint> points = new List<IPoint>(); double distance = 50; double interval = 50; while (distance < pPolyline.Length) { IPoint pPoint = new ESRI.ArcGIS.Geometry.Point(); pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, distance, false, pPoint); points.Add(pPoint); distance += interval; } // 分割线要素 foreach (IPoint pPoint in points) { IFeatureEdit pFeatureEdit = pFeature as IFeatureEdit; ISet pSet = pFeatureEdit.Split(pPoint); pSet.Reset(); pFeature = GetFeatureByDistance(pSet); } // 刷新地图 m_hookHelper.ActiveView.Refresh(); } // 获取Set中距离较长的线要素 private IFeature GetFeatureByDistance(ISet pSet) { IFeature pFirstFeature = pSet.Next() as IFeature; IFeature pSecondFeature = pSet.Next() as IFeature; IPolyline pFirstPolyline = pFirstFeature.ShapeCopy as IPolyline; IPolyline pSecondPolyline = pSecondFeature.ShapeCopy as IPolyline; return pFirstPolyline.Length <= pSecondPolyline.Length ? pSecondFeature : pFirstFeature; } #endregion } }
运行结果如下图所示:
比例分割如下图所示:
其实和按距离分割的逻辑差不多,唯一的区别就是在获取分割点时改为按比例获取
,其代码如下:
using ESRI.ArcGIS.ADF.BaseClasses; using ESRI.ArcGIS.ADF.CATIDs; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; namespace WindowsFormsApplication1.Command { /// <summary> /// Summary description for SplitByRatioCommand. /// </summary> [Guid("d4624838-4abc-458e-b6cf-fb5d78562e96")] [ClassInterface(ClassInterfaceType.None)] [ProgId("WindowsFormsApplication1.Command.SplitByRatioCommand")] public sealed class SplitByRatioCommand : BaseCommand { #region COM Registration Function(s) [ComRegisterFunction()] [ComVisible(false)] static void RegisterFunction(Type registerType) { // Required for ArcGIS Component Category Registrar support ArcGISCategoryRegistration(registerType); // // TODO: Add any COM registration code here // } [ComUnregisterFunction()] [ComVisible(false)] static void UnregisterFunction(Type registerType) { // Required for ArcGIS Component Category Registrar support ArcGISCategoryUnregistration(registerType); // // TODO: Add any COM unregistration code here // } #region ArcGIS Component Category Registrar generated code /// <summary> /// Required method for ArcGIS Component Category registration - /// Do not modify the contents of this method with the code editor. /// </summary> private static void ArcGISCategoryRegistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); ControlsCommands.Register(regKey); } /// <summary> /// Required method for ArcGIS Component Category unregistration - /// Do not modify the contents of this method with the code editor. /// </summary> private static void ArcGISCategoryUnregistration(Type registerType) { string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID); ControlsCommands.Unregister(regKey); } #endregion #endregion private IHookHelper m_hookHelper; public SplitByRatioCommand() { // // TODO: Define values for the public properties // base.m_category = ""; //localizable text base.m_caption = ""; //localizable text base.m_message = ""; //localizable text base.m_toolTip = ""; //localizable text base.m_name = ""; //unique id, non-localizable (e.g. "MyCategory_MyCommand") try { // // TODO: change bitmap name if necessary // string bitmapResourceName = GetType().Name + ".bmp"; base.m_bitmap = new Bitmap(GetType(), bitmapResourceName); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap"); } } #region Overridden Class Methods /// <summary> /// Occurs when this command is created /// </summary> /// <param name="hook">Instance of the application</param> public override void OnCreate(object hook) { if (hook == null) return; if (m_hookHelper == null) m_hookHelper = new HookHelperClass(); m_hookHelper.Hook = hook; } /// <summary> /// Occurs when this command is clicked /// </summary> public override void OnClick() { if (m_hookHelper.FocusMap.SelectionCount != 1) { MessageBox.Show("请选择1条线要素进行分割", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 获取被选择的要素 IEnumFeature pEnumFeature = m_hookHelper.FocusMap.FeatureSelection as IEnumFeature; pEnumFeature.Reset(); IFeature pFeature = pEnumFeature.Next(); if (pFeature.Shape is IPoint || pFeature.Shape is IPolygon) { MessageBox.Show("请选择1条线要素进行分割", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // 获取分割点 IPolyline pPolyline = pFeature.ShapeCopy as IPolyline; List<IPoint> points = new List<IPoint>(); double ratio = 0.2; double interval = 0.2; while (ratio < 1) { IPoint pPoint = new ESRI.ArcGIS.Geometry.Point(); pPolyline.QueryPoint(esriSegmentExtension.esriNoExtension, ratio, true, pPoint); points.Add(pPoint); ratio += interval; } // 分割线要素 foreach (IPoint pPoint in points) { IFeatureEdit pFeatureEdit = pFeature as IFeatureEdit; ISet pSet = pFeatureEdit.Split(pPoint); pSet.Reset(); pFeature = GetFeatureByDistance(pSet); } // 刷新地图 m_hookHelper.ActiveView.Refresh(); } // 获取Set中距离较长的线要素 private IFeature GetFeatureByDistance(ISet pSet) { IFeature pFirstFeature = pSet.Next() as IFeature; IFeature pSecondFeature = pSet.Next() as IFeature; IPolyline pFirstPolyline = pFirstFeature.ShapeCopy as IPolyline; IPolyline pSecondPolyline = pSecondFeature.ShapeCopy as IPolyline; return pFirstPolyline.Length <= pSecondPolyline.Length ? pSecondFeature : pFirstFeature; } #endregion } }
运行结果如下图所示:
如果你想实现:对一条线段进行等比例分割
,那么只需要修改一下分割比例即可。比如对1
条线段5
等分只需要将分割比例设置为0.2
即可:
double ratio = 0.2; double interval = 0.2;
运行结果如下图所示: