如何将一个图层上的一行的ToPoint和FromPoint添加到另一个图层/要素类

时间:2010-06-08 09:06:03

标签: arcobjects

我有道路图层。 我需要指向另一个道路相交的点层。 如何将这些点添加到现有点图层。

手头我有线图层,线要素/ To和From Points以及点图层。 我只需要一个指针来指示如何在点图层中创建点。

我正在使用C#

谢谢。

1 个答案:

答案 0 :(得分:2)

下面的代码说明了通过使用扩展方法实现此目的的方法。 ArcObjects API经常被批评为接口太多,导致代码可读性降低。我相信扩展方法可以解决许多这些问题。缺点是阅读代码的人无法轻易区分扩展方法和API的一部分方法。

我不确定问题的背景,但是如果你要为街道交叉点创建点,你可以考虑使用不同的点哈希函数。这将允许道路交叉点,其中道路在多于一个点处交叉由单个点表示。这类似于地图拓扑中使用的群集容差。

我还没有真正了解一个很好的继承方法,用于调用自定义异常的基础构造函数。任何建议都会受到赞赏。

using System;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.Framework;
using System.Windows.Forms;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using System.Collections.Generic;
using ESRI.ArcGIS.Editor;

namespace IGG.SurveyTools
{
    /// <summary>
    /// Summary description for TestCommand.
    /// </summary>
    [ProgId("IGG.SurveyTools.TestCommand")]
    public sealed class TestCommand : BaseCommand
    {
        private IEditor m_Editor;
        public TestCommand()
        {
            //
            // TODO: Define values for the public properties
            //
            base.m_category = ""; //localizable text
            base.m_caption = "Add End points";  //localizable text
            base.m_message = "";  //localizable text 
            base.m_toolTip = "";  //localizable text 
            base.m_name = "";   //unique id, non-localizable (e.g. "MyCategory_MyCommand")
        }

        #region Overriden Class Methods

        /// <summary>
        /// Occurs when this command is created
        /// </summary>
        /// <param name="hook">Instance of the application</param>
        public override void OnCreate(object hook)
        {
            IApplication app = hook as IApplication;
            if (app == null)
                return;
            m_Editor = app.FindExtensionByName("ESRI Object Editor") as IEditor;
        }
        public override bool Enabled
        {
            get
            {
                return (m_Editor != null && m_Editor.EditState == esriEditState.esriStateEditing);
            }
        }
        public override void OnClick()
        {
            try
            {
                string fmt = "{0},{1}";

                IMxDocument mxDoc = (IMxDocument)m_Editor.Parent.Document;

                IFeatureLayer polylineLayer = mxDoc.FocusMap.FindFLayer("My Polylines");
                IFeatureLayer pointLayer = mxDoc.FocusMap.FindFLayer("My Points");
                if(((IDataset)pointLayer.FeatureClass).Workspace != m_Editor.EditWorkspace)
                {
                    MessageBox.Show(new Win32Win(m_Editor), "Points layer is not being edited");
                    return;
                }
                Dictionary<string, IPoint> endPoints =  polylineLayer.GetEndPoints(fmt);
                if (endPoints.Count == 0)
                {
                    MessageBox.Show("no end points found");
                    return;
                }
                Dictionary<string,IPoint> existingPoints = pointLayer.GetPoints(fmt);
                Dictionary<string,IPoint> newPoints = endPoints.Subtract(existingPoints);
                if(newPoints.Count == 0)
                {
                    MessageBox.Show(new Win32Win(m_Editor.Parent),"all endpoints are present in pointslayer");
                    return;
                }

                m_Editor.StartOperation();
                try
                {
                    pointLayer.FeatureClass.PutPoints(newPoints.Values);
                    m_Editor.StopOperation(String.Format("Added {0} new endpoints", newPoints.Count));
                    ((IActiveView)m_Editor.Map).Refresh();
                }
                catch(Exception ex)
                {
                    m_Editor.AbortOperation();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(new Win32Win(m_Editor), ex.Message + Environment.NewLine + ex.StackTrace);
            }
        }        
        #endregion

    }

    public class Win32Win : IWin32Window
    {
        private IntPtr m_handle;
        public Win32Win(IApplication app) { m_handle = new IntPtr(app.hWnd); }
        public IntPtr Handle { get { return m_handle; } }
        public Win32Win(int hwnd) { m_handle = new IntPtr(hwnd); }
        public Win32Win(IEditor editor) { m_handle = new IntPtr(editor.Parent.hWnd); }
    }

    public class LayerNotFoundException : Exception
    {
        public LayerNotFoundException(string lyrName) 
            : base("Layer not found: " + lyrName) 
        { 
        }
    }

    public class FeatureLayerNotFoundException : LayerNotFoundException
    {
        public FeatureLayerNotFoundException(string lyrName)
            : base(lyrName)
        {
        }
    }

    public static class MyExtensions
    {
        public static void PutPoints(this IFeatureClass fc, IEnumerable<IPoint> pnts)
        {
            IFeatureCursor fCur = fc.Insert(false);
            IFeatureBuffer buff = fc.CreateFeatureBuffer();
            foreach (IPoint pnt in pnts)
            {
                buff.Shape = pnt;
                fCur.InsertFeature(buff);
            }
            fCur.Flush();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
        }

        /// <summary>
        /// returns first layer in map with case-insensitive name
        /// </summary>
        /// <param name="map"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static ILayer FindLayer(this IMap map, string name)
        {
            if (map.LayerCount == 0)
                throw new LayerNotFoundException(name);
            IEnumLayer enumLayer = map.get_Layers(null, true);
            ILayer layer;
            while ((layer = enumLayer.Next()) != null)
            {
                if (layer.Name.Trim().ToUpper() == name.Trim().ToUpper())
                    return layer;
            }
            throw new LayerNotFoundException(name);
        }

        public static IFeatureLayer FindFLayer(this IMap map, string name)
        {
            IFeatureLayer fLayer = map.FindLayer(name) as IFeatureLayer;
            if (fLayer == null)
                throw new FeatureLayerNotFoundException(name);
            return fLayer;
        }

        public static Dictionary<string, IPoint> GetPoints(this IFeatureLayer fLayer, string fmt)
        {
            if (fLayer.FeatureClass == null
                || fLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPoint)
                throw new Exception("bad point layer: " + fLayer.Name);

            Dictionary<string, IPoint> outDict = new Dictionary<string, IPoint>();
            IFeatureCursor fCur = fLayer.FeatureClass.Search(null, false);
            IFeature feat;
            while ((feat = fCur.NextFeature()) != null)
            {
                outDict.AddPoint((IPoint)feat.ShapeCopy,fmt);
            }
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
            return outDict;
        }

        public static Dictionary<string, IPoint> GetEndPoints(this IFeatureLayer fLayer, string fmt)
        {
            if (fLayer.FeatureClass == null 
                || fLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPolyline)
                throw new Exception("bad polyline layer: " + fLayer.Name);

            Dictionary<string, IPoint> outDict = new Dictionary<string, IPoint>();
            IFeatureCursor fCur = fLayer.FeatureClass.Search(null, false);
            IFeature feat;
            while ((feat = fCur.NextFeature()) != null)
            {
                IPolyline polyline = (IPolyline)feat.ShapeCopy;
                if (polyline == null || polyline.IsEmpty)
                    continue;
                outDict.AddPoint(polyline.FromPoint,fmt);
                outDict.AddPoint(polyline.ToPoint,fmt);
            }
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(fCur);
            return outDict;
        }
        public static string Hash(this IPoint pnt, string fmt)
        {
            // use different formatting options to do quick and dirty clustering
            return String.Format(fmt, pnt.X, pnt.Y);
        }

        public static void AddPoint(this Dictionary<string,IPoint> dict ,IPoint pnt, string fmt)
        {
            string hash = pnt.Hash(fmt);
            if (!dict.ContainsKey(hash))
                dict.Add(hash, pnt);
        }
        public static Dictionary<string, IPoint> Subtract(this Dictionary<string, IPoint> inDict, Dictionary<string, IPoint> otherDict)
        {
            Dictionary<string, IPoint> outDict = new Dictionary<string, IPoint>();
            foreach (KeyValuePair<string, IPoint> kvp in inDict)
            {
                if (!otherDict.ContainsKey(kvp.Key))
                    outDict.Add(kvp.Key, kvp.Value);
            }
            return outDict;
        }
    }
}