2010-06-08 5 views
1

J'ai une couche de routes. J'ai besoin d'ajouter un point à un autre point, couche où les routes se croisent. Comment puis-je ajouter de tels points à la couche de points existante.Comment ajouter ToPoint et FromPoint d'une ligne sur une couche à une autre couche/classe d'entités

J'ai en main le calque de ligne, la fonction de ligne/Points de départ et d'arrivée et le calque de points. J'ai juste besoin d'un pointeur sur la façon de créer des points dans la couche de points. J'utilise C#

Merci.

Répondre

2

Le code ci-dessous illustre les façons de le faire en utilisant des méthodes d'extension. L'API ArcObjects est souvent critiquée pour avoir trop d'interfaces, ce qui entraîne un code moins lisible. Je crois que les méthodes de vulgarisation peuvent répondre à plusieurs de ces préoccupations. L'inconvénient est que les personnes lisant le code ne peuvent pas distinguer facilement les méthodes d'extension et les méthodes qui font partie de l'API.

Je ne suis pas sûr du contexte de votre problème, mais si vous créez des points pour des intersections de rues, vous pouvez envisager d'utiliser une autre fonction de hachage de points. Cela permettrait aux intersections routières où les routes se croisent à plus d'un point d'être représentées par un seul point. Cela serait analogue à la tolérance de cluster utilisée dans les topologies de carte.

Je ne me suis pas vraiment concentré sur une méthode d'héritage intéressante pour appeler des constructeurs de base pour des exceptions personnalisées. Toutes les suggestions seraient appréciées.

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

Impressionnant! Je vais donner un coup de pied à ce code dès que je serai au travail demain matin. Ceci est mon premier projet Arc, donc je trouve toujours mon exploit, mais j'ai déjà commencé à extraire des tas de choses dans des méthodes d'extension qui rendent mon code beaucoup plus compréhensible. Je ne suis pas sûr de comprendre ce que vous voulez dire par les constructeurs de base pour les exceptions personnalisées. Ce que vous avez fait m'a l'air parfaitement bien. La seule chose que je pourrais changer est d'hériter de ApplicationException à la place, pour indiquer avec force que c'est une exception de ma pile d'applications vers le haut, et non pas d'en bas. Mais c'est trivial. –

+0

Pour votre méthode GetPoints, ne pourriez-vous pas utiliser un curseur de recyclage parce que vous faites des copies des points de toute façon? –

+0

Oui, cela pourrait être le recyclage, et le ferait courir plus vite. Aussi, pour accélérer les requêtes, vous pouvez passer un IQueryFilter à la méthode Search, et assurez-vous de définir IQueryFilter.SubFields pour qu'il ne contienne que le champ ObjectID. Par défaut, le curseur récupère tous les champs. –

Questions connexes