ArcEngine中實現捕捉功能

來源:互聯網
上載者:User

捕捉功能主要使用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);
  }
  

 }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.