zoukankan      html  css  js  c++  java
  • ArcEngine中实现捕捉功能



    捕捉功能主要使用ArcEngine中的两个接口


    1. IHitTest用于作点击测试
    2. IFeatureCache 用于建立做缓存
    由于数据库中有多个FeatureClass ,而每个FeatureClass又可以做多种点击测试
    所以这里有会有好几种捕捉方案。
    我们称呼每一个可以执行捕捉的对象叫捕捉代理,所有的代理在一个捕捉环境中
    方案1:每个代理负责测试一种FeatureClass的一种点击方式
    方案2:每个代理负责测试一种FeatureClass的所有点击方式
    方案3:一代理负责测试所有的FeatureClass的一种点击方式
    方案4:一个代理负责测试所有FeatureClass的所有点击方式
    在实际使用过程中 我们使用的是第一种方案。但是我个人认为第二种方案比较好。当然这只是个人推测
    没有测试数据证明。
    下面给出第一种方案的代码:
    /// <summary>
     /// IFeatureSnapAgent 的摘要说明。
     /// </summary>
     public interface IFeatureSnapAgent:ISnapAgent,ISnapAgentFeedback
     {
      IFeatureCache FeatureCache
      {
       get;
      }
      IFeatureClass  FeatureClass
      {
       get;
       set;
      }
      esriGeometryHitPartType HitPartType
      {
       get;
       set;
      }
      /// <summary>
      /// 为捕捉连接事件,当捕捉发生的时候,就会触发事件。
      /// </summary>
      /// <param name="handler"></param>
      void AddSnapedEventHandler(GeometrySnapedEventHandler handler);
      /// <summary>
      /// 不再监听捕捉事件
      /// </summary>
      /// <param name="handler"></param>
      void RemoveSnapedEventHandler(GeometrySnapedEventHandler handler);
     }
     /// <summary>
     /// 默认的要素捕捉代理
     /// </summary>
     public class DefaultFeatureSnapAgent :IFeatureSnapAgent,IEditEvents,ESRI.ArcGIS .esriSystem .IPersistVariant  
     {
      #region 构造函数
      /// <summary>
      /// 为代理指定别名。注意该代理目前还没有关联到任何目标FeatureClass
      /// 要使得该代理起作用,必须要为他设置FeatureClass.
      /// </summary>
      /// <param name="name">名称(请确保唯一)</param>
      public DefaultFeatureSnapAgent(string name):this(name,null)
      {
       
      }
      /// <summary>
      /// 将使用该FeatureClass的别名做代理的名称
      /// </summary>
      /// <param name="feaClass"></param>
      public DefaultFeatureSnapAgent(IFeatureClass feaClass):this(feaClass.AliasName,feaClass)
      {


      }
      /// <summary>
      /// 完全初始化捕捉代理
      /// </summary>
      /// <param name="name">名称(请确保唯一)</param>
      /// <param name="feaClass">目标FeatureClass</param>
      public DefaultFeatureSnapAgent(string name,IFeatureClass feaClass)
      {
       m_snapAgentName=name;
       m_bCacheHasCreated=false;
       m_hitPartType=esriGeometryHitPartType.esriGeometryPartNone;
       this.m_isSnapWorking=true;
       this.m_featureClass=feaClass;
       this.m_snapFeedbackText="";
       
      }
      #endregion
      #region IFeatureSnapAgent 成员
      private event GeometrySnapedEventHandler    m_snapSubsciber;
      /// <summary>
      /// FeatureClass缓冲区。
      /// </summary>
      private IFeatureCache m_featureCache;
      /// <summary>
      /// 该代理将捕捉在该FeatureClass上的Feature.和Geometry
      /// </summary>
      private IFeatureClass m_featureClass;
      /// <summary>
      /// 点击测试的有效类型。
      /// </summary>
      protected esriGeometryHitPartType m_hitPartType;
      /// <summary>
      /// 缓冲区对象是否已经被创建了。跟是否建立了缓冲没有关系。
      /// </summary>
      private bool   m_bCacheHasCreated;
      
      /// <summary>
      /// 缓冲区对象
      /// </summary>
      public IFeatureCache FeatureCache
      {
       get
       {
        return m_featureCache;
       }
      }
      /// <summary>
      /// 目标FeatureClass。SnapAgent将针对该FeatureClass做捕捉
      /// </summary>
      public IFeatureClass FeatureClass
      {
       get
       {
        return m_featureClass;
       }
       set
       {
        m_featureClass=value;
       }
      }
      
      /// <summary>
      /// 点击测试类型。哪些点击类型会被测试
      /// </summary>
      public ESRI.ArcGIS.Geometry.esriGeometryHitPartType HitPartType
      {
       get
       {
        // TODO:  添加 DefaultFeatureSnapAgent.HitPartType getter 实现
        return m_hitPartType;
       }
       set
       {
        
        m_hitPartType=value;
       }
      }


      /// <summary>
      ///  创建缓冲区对象。
      /// </summary>
      private void CreateFeatureCache()
      {
       m_featureCache=new ESRI.ArcGIS.Carto.FeatureCacheClass();
       m_bCacheHasCreated=true;
      }
      /// <summary>
      ///  填充缓冲区。如果还没有创建缓冲区对象,就先创建缓冲区对象。
      ///  如果已经拥有缓冲区,而且当前点依然在该缓冲区内部,那么不会填充生成新的缓冲。
      ///  由于缓冲是在捕捉方法内部被使用的。所以可以保证m_featureClass必然不会为空引用。
      /// </summary>
      /// <param name="point">当前点</param>
      /// <param name="size">缓冲区大小</param>
      private void FillCache(IPoint point,double size)
      {
       if(!m_bCacheHasCreated)
       {
        CreateFeatureCache();
       }
       if(!m_featureCache.Contains (point))
       {
        m_featureCache.Initialize(point,size);
        m_featureCache.AddFeatures(this.m_featureClass);
       }
      }
      /// <summary>
      /// 添加事件侦听者。捕捉发生后,事件将会被发送到该侦听者。
      /// </summary>
      /// <param name="handler"></param>
      public void AddSnapedEventHandler(GeometrySnapedEventHandler handler)
      {
       m_snapSubsciber+=handler;
      }
      /// <summary>
      /// 移去事件侦听者。
      /// </summary>
      /// <param name="handler"></param>
      public void RemoveSnapedEventHandler(GeometrySnapedEventHandler handler)
      {


       m_snapSubsciber-=handler;
      }
      #endregion
      #region ISnapAgent 成员
      private string m_snapAgentName;
      /// <summary>
      /// SnapAgent是否在工作。代表用户是打开还是关闭了SnapAgent
      /// 初始化的时候默认是打开的。
      /// </summary>
      private bool   m_isSnapWorking;
      public string Name
      {
       get
       {
        return m_snapAgentName;
       }
      }
      public bool IsWorking()
      {
       return this.m_isSnapWorking ;
      }
      /// <summary>
      ///  捕捉。
      /// </summary>
      /// <param name="metry"></param>
      /// <param name="snapPoint"></param>
      /// <param name="tolerance"></param>
      /// <returns></returns>
      public virtual bool Snap(IGeometry metry, IPoint snapPoint, double tolerance)
      {
       /*
        * 捕捉的过程:
        * 首先使用当前位置、目标图层、和误差的10倍构造一个缓冲区。
        * 对缓冲区中的每个Feature,找到他包含的每一个Geometry。
        * 对Geometry做点击测试。
        */
       if(!this.m_isSnapWorking)
       {
        //捕捉代理已经被用户关闭了。不会有任何捕捉动作发生
        return false;
       }
       if(m_featureClass==null)
       {
        //没有目标图层。不能做捕捉动作。此时应该报错
        //但是目前只是返回false。
        return false;
       }
       FillCache(snapPoint,tolerance*10);
       //当前被测试的Feature
       IFeature            feature=null;
       //当前被测试的几何图形
       IGeometry           curMetry=null;
       //当前被测试的Feature的索引和缓冲区中拥有的feature的个数。
       int featureIndex,featureCount;
       featureCount=m_featureCache.Count;
       for(featureIndex=0;featureIndex<featureCount;featureIndex++)
       {
        feature=m_featureCache.get_Feature(featureIndex);
        if(feature!=null)
        {
         curMetry=feature.Shape;
         IPoint hitPoint=new ESRI.ArcGIS .Geometry.PointClass ();
         double hitDist=0;
         int hitPartIndex=-1;
         bool bRightSide=false;
         int hitSegmentIndex=-1;
         IHitTest hitTest=(IHitTest)curMetry;
         if(hitTest.HitTest (snapPoint,tolerance,this.m_hitPartType,hitPoint,ref hitDist
          ,ref hitPartIndex,ref hitSegmentIndex,ref bRightSide))
         {


          GeometrySnapEventArgs args=new GeometrySnapEventArgs (hitPoint,curMetry,
           feature,this.m_featureClass,hitPartIndex,hitSegmentIndex,tolerance,
           hitDist,this.m_hitPartType,bRightSide);
          SetFeedback("FeatureSnapAgent"+this.Name+"捕捉到了!");
          LaunchSnapEvent(args);  
          snapPoint.X=hitPoint.X;
          snapPoint.Y=hitPoint.Y;
          return true;
         }
         
         
         
         
        }
       }


       
       return false;
      }
      
      /// <summary>
      /// 打开捕捉代理
      /// </summary>
      public void TurnOn()
      {
       this.m_isSnapWorking=true;
      }
      /// <summary>
      /// 关闭捕捉代理
      /// </summary>
      public void TurnOff()
      {
       this.m_isSnapWorking =false;
      }
      private void LaunchSnapEvent(SnapEventArgs args)
      {
       
       if(this.m_snapSubsciber!=null&&args!=null)
       {
        this.m_snapSubsciber(this,args);
       }
      }
      #endregion
      #region Object 成员
      /// <summary>
      /// 名字是一个agent的唯一标志。
      /// </summary>
      /// <param name="obj"></param>
      /// <returns></returns>
      public override bool Equals(object obj)
      {
       if(! (obj is DefaultFeatureSnapAgent))
       {
        return false;
       }
       DefaultFeatureSnapAgent agent=(DefaultFeatureSnapAgent)obj;
       return this.m_snapAgentName.Equals(agent.m_snapAgentName);
       
      }
      
      public override int GetHashCode()
      {
       return this.m_snapAgentName.GetHashCode();
      }
      #endregion
      #region IEditEvents 成员


      public void AfterDrawSketch(IObject obj)
      {
       // TODO:  添加 DefaultFeatureSnapAgent.AfterDrawSketch 实现
      }


      public void OnChangeFeature(IObject obj)
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnChangeFeature 实现
      }


      public void OnConflictsDetected()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnConflictsDetected 实现
      }


      public void OnCreateFeature(IObject obj)
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnCreateFeature 实现
      }


      public void OnCurrentLayerChanged()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnCurrentLayerChanged 实现
      }


      public void OnCurrentTaskChanged()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnCurrentTaskChanged 实现
      }


      public void OnDeleteFeature(IObject obj)
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnDeleteFeature 实现
      }


      public void OnRedo()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnRedo 实现
      }


      public void OnSelectionChanged()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnSelectionChanged 实现
      }


      public void OnSketchFinished()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnSketchFinished 实现
      }


      public void OnSketchModified()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnSketchModified 实现
      }


      public void OnStartEditing()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnStartEditing 实现
      }


      public void OnStopEditing(Boolean save)
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnStopEditing 实现
      }


      public void OnUndo()
      {
       // TODO:  添加 DefaultFeatureSnapAgent.OnUndo 实现
      }


      #endregion
      #region ISnapFeedback 成员
      private string m_snapFeedbackText;
      public string SnapText
      {
       get
       {
        return this.m_snapFeedbackText;
       }
      }
      private void SetFeedback(string feedback)
      {
       this.m_snapFeedbackText=feedback;
      }
      #endregion
      #region IPersistVariant 成员
      public ESRI.ArcGIS .esriSystem .UID  ID
      {
       get
       {
        ESRI.ArcGIS .esriSystem .UID uid=new ESRI.ArcGIS .esriSystem .UIDClass ();
        uid.Value ="ls.gis.Editor.DefaultFeatureSnapAgent"+this.m_snapAgentName;
        return uid;
       }
      }
      public void Load(ESRI.ArcGIS .esriSystem .IVariantStream vs)
      {
       this.m_snapAgentName =(string)vs.Read ();
       this.m_isSnapWorking =(bool)vs.Read ();
       string hitPartStr=(string)vs.Read ();
       this.m_hitPartType =(esriGeometryHitPartType)Enum.Parse (this.m_hitPartType .GetType (),hitPartStr,false);
       bool hasFeatureClass=(bool)vs.Read ();
       if(hasFeatureClass)
       {
        ESRI.ArcGIS .esriSystem .IName name=(ESRI.ArcGIS .esriSystem .IName)vs.Read ();
        this.m_featureClass =(IFeatureClass)name.Open ();
       }
      }
      public void Save(ESRI.ArcGIS .esriSystem .IVariantStream vs)
      {
       vs.Write (this.m_snapAgentName);
       vs.Write (this.m_isSnapWorking );
       vs.Write (this.m_hitPartType.ToString ());
       if(this.m_featureClass !=null)
       {
        vs.Write (true);
        IDataset dataset=(IDataset)this.m_featureClass ;
        vs.Write (dataset.FullName );
       }
       else
       {
        vs.Write (false);
       }
       


      }
      #endregion
      
     }



     public class DefaultSnapAgentEnvironment:ISnapAgentEnvironment
     {
      private double     m_tolerance;
      private SnapToleranceUnit   m_snapToleranceUnit;
      private ArrayList  m_snapAgentArray;
      /// <summary>
      /// 用于转换误差单位
      /// </summary>
      private IActiveView m_activeView;
      /// <summary>
      /// 如果误差单位为地图单位,那么可以调用这个构造函数。
      /// 如果误差单位为象素。那么应该调用有参数的构造方法。
      /// 如果在调用时不能确定参数activeView,那么也可以先调用该方法构造对象。
      /// 然后用属性ActiveView来设置该参数的值。
      /// </summary>
      public DefaultSnapAgentEnvironment():this(null)
      {
       
      }
      public DefaultSnapAgentEnvironment(IActiveView activeView)
      {
       m_snapAgentArray=new ArrayList ();
       m_tolerance=7;
       m_snapToleranceUnit=SnapToleranceUnit.UnitPixels;
       this.m_activeView=activeView;
      }
      /// <summary>
      ///  用于转换误差的单位。如果没有设置,或者设置为null,
      ///  那么误差的单位将不会被转换,而直接被认为是地图单位。
      /// </summary>
      public IActiveView ActivView
      {
       set
       {
        this.m_activeView=value;
       }
       get
       {
        return this.m_activeView;
       }
      }
      #region ISnapAgentEnvironment 成员  


      public void AddSnapAgent(ISnapAgent agent)
      {
       if(agent==null)
       {
        return;
       }
       if(this.m_snapAgentArray.Contains(agent))
       {
        return;
       }
       this.m_snapAgentArray.Add(agent);
      }


      public void ClearSnapAgent()
      {
       this.m_snapAgentArray.Clear();
      }
      /// <summary>
      /// 如果索引越界,那么返回null,而不会抛出异常。
      /// </summary>
      /// <param name="index"></param>
      /// <returns></returns>
      public ISnapAgent GetSnapAgent(int index)
      {
       if(index<this.m_snapAgentArray.Count&&index>=0)
       {
        return (ISnapAgent)this.m_snapAgentArray[index];
       }
       else
       {
        return null;
       }
      }
      /// <summary>
      /// 如果不存在,回返回null
      /// </summary>
      /// <param name="name"></param>
      /// <returns></returns>
      ISnapAgent ls.gis.Editor.ISnapAgentEnvironment.GetSnapAgent(string name)
      {
       ISnapAgent retAgent=null;
       int retAgentIndex=-1;
       for(int index=0; index<this.m_snapAgentArray.Count;index++)
       {
        retAgent=(ISnapAgent)this.m_snapAgentArray[index];
        if(retAgent.Name.Equals(name))
        {
         retAgentIndex=index;
         break;
        }
       }
       return GetSnapAgent(retAgentIndex);
      }


      public void RemoveSnapAgent(string name)
      {
       ISnapAgent retAgent=null;
       int retAgentIndex=-1;
       for(int index=0; index<this.m_snapAgentArray.Count;index++)
       {
        retAgent=(ISnapAgent)this.m_snapAgentArray[index];
        if(retAgent.Name.Equals(name))
        {
         retAgentIndex=index;
         break;
        }
       }
       this.RemoveSnapAgent(retAgentIndex);
      }
      /// <summary>
      ///
      /// </summary>
      /// <param name="index"></param>
      public void RemoveSnapAgent(int index)
      {
       if(index<0||index>=this.m_snapAgentArray.Count)
       {
        return ;
       }
       this.m_snapAgentArray.RemoveAt(index);
      }


      public bool SnapPoint(IPoint point)
      {
       for(int index=0;index<this.m_snapAgentArray.Count;index++)
       {
        ISnapAgent agent=(ISnapAgent)this.m_snapAgentArray[index];
        if(agent.Snap(null,point,ConvertTolerance(this.m_tolerance)))
        {      
         return true;
        }
       }
       return false;
      }


      public int SnapAgentCount
      {
       get
       {
        // TODO:  添加 FeatureSnapAgentEnvironment.SnapAgentCount getter 实现
        return this.m_snapAgentArray.Count;
       }
      }


      public double SnapAgentTolerance
      {
       get
       {
        // TODO:  添加 FeatureSnapAgentEnvironment.SnapAgentTolerance getter 实现
        return this.m_tolerance;
       }
       set
       {
        this.m_tolerance=value;
       }
      }
      public SnapToleranceUnit SnapToleranceUnit
      {
       get
       {
        return this.m_snapToleranceUnit;
       }
       set
       {
        this.m_snapToleranceUnit=value;
       }
      }
      
      #endregion
      private double ConvertTolerance(double tolerance)
      {
       double retValue=tolerance;
       if(this.m_activeView ==null)
       {
        //不能做转换
        retValue=tolerance;
       }
       else
       {
        if(this.m_snapToleranceUnit.Equals (SnapToleranceUnit.UnitPixels))
        {
         //需要转换
         retValue=ls.gis.Common .CommonCooperation.ConvertPixelsToMapUnits (this.m_activeView ,tolerance);
        }
        else
        { //不需要转换
         retValue=tolerance;
        }
       }
       return retValue;
      }
      private double ConvertTolerance()
      {
       return this.ConvertTolerance (this.m_tolerance);
      }
      


     }

  • 相关阅读:
    PHP线程安全
    Oracle中MD5+Base64加密实现
    1002. A+B for Polynomials (25)
    1001. A+B Format (20)
    Rails,uva 514
    Database,Uva1592
    Hello World for U
    D3.js 力导向图
    从零开始CSS(一 2016/9/21)
    从零开始HTML(三 2016/9/20)
  • 原文地址:https://www.cnblogs.com/holygis/p/1968067.html
Copyright © 2011-2022 走看看