• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
bobird的学习笔记
博客园    首页    新随笔    联系   管理    订阅  订阅
ArcEngine 捕捉

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

1. IHitTest用于作点击测试
2. IFeatureCache 用于建立做缓存
由于数据库中有多个FeatureClass ,而每个FeatureClass又可以做多种点击测试
所以这里有会有好几种捕捉方案。
我们称呼每一个可以执行捕捉的对象叫捕捉代理,所有的代理在一个捕捉环境中
方案1:每个代理负责测试一种FeatureClass的一种点击方式
方案2:每个代理负责测试一种FeatureClass的所有点击方式
方案3:一代理负责测试所有的FeatureClass的一种点击方式
方案4:一个代理负责测试所有FeatureClass的所有点击方式
在实际使用过程中 我们使用的是第一种方案。但是我个人认为第二种方案比较好。当然这只是个人推测
没有测试数据证明。
下面给出第一种方案的代码:

未测试过,部门接口只是用与Desktop

/// <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);
  }
  

 }

 

posted on 2013-06-26 15:08  bobird  阅读(411)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3