ArcObjects SDK開發 017 在ArcObject SDK 中使用Toolbox

2022-12-18 15:00:19

1、Geoprocessor和IGPProcess

Geoprocessor是ArcObjects SDK中定義Tool執行器。IGPProcess介面是ArcObjects SDK中定義的ArcTool介面。也就是說ArcObjects SDK定義的ArcTool都會繼承該介面實現。理論上,在ArcToolbox的出現的系統工具都應該可以在SDK中找到。

Geoprocessor如何使用呢?參考下面的程式碼。

private static Geoprocessor _Geoprocessor = null;
/// <summary>
/// 實際的地理處理器
/// </summary>
public Geoprocessor Geoprocessor
{
    get
    {
        if (_Geoprocessor == null)
        {
            _Geoprocessor = new Geoprocessor
            {
                OverwriteOutput = true
            };
        }
        return _Geoprocessor;
    }
}
public object ExecuteByGP(IGPProcess pGPProcess)
{
    try
    {
        return Geoprocessor.Execute(pGPProcess, null);
    }
    catch
    {
        object mySeverity = null;
        string myMessage = Geoprocessor.GetMessages(ref mySeverity);
        throw new Exception(myMessage);
    }
}

2、以Buffer為例

ArcToolBox的對應的類在SDK中找不到,我們一般從ArcMap上著手。首先先在ArcMap上的Toolbox中找到Buffer工具,並開啟。如下圖所示。

image1.png

我們可以通過點選Tool Help按鈕,檢視該工具的具體用法。特別是引數說明部分。通過幫助中的資訊,分析出屬於那個dll檔案,如果沒有參照的話,參照下。如下圖所示。

image2.png

後面有個Analysis,那麼該功能在ArcObjects SDK中是被定義在ESRI.ArcGIS.AnalysisTools.dll中的。例如Dissolve工具,後面的括號內是Data Management,那麼該工具被定義到了ESRI.ArcGIS.DataManagementTools.dll中。

我們到SDK中看下Buffer是怎麼定義的。

using System.IO;
using System.Reflection;
using System.Xml;
using ESRI.ArcGIS.Geoprocessor;

namespace ESRI.ArcGIS.AnalysisTools
{
    public class Buffer : IGPProcess
    {
        private object[] m_gpParameters;

        private string m_ToolboxDirectory;

        public object in_features
        {
            get
            {
                return m_gpParameters[0];
            }
            set
            {
                m_gpParameters[0] = value;
            }
        }

        public object out_feature_class
        {
            get
            {
                return m_gpParameters[1];
            }
            set
            {
                m_gpParameters[1] = value;
            }
        }

        public object buffer_distance_or_field
        {
            get
            {
                return m_gpParameters[2];
            }
            set
            {
                m_gpParameters[2] = value;
            }
        }

        public string line_side
        {
            get
            {
                return m_gpParameters[3] as string;
            }
            set
            {
                m_gpParameters[3] = value;
            }
        }

        public string line_end_type
        {
            get
            {
                return m_gpParameters[4] as string;
            }
            set
            {
                m_gpParameters[4] = value;
            }
        }

        public string dissolve_option
        {
            get
            {
                return m_gpParameters[5] as string;
            }
            set
            {
                m_gpParameters[5] = value;
            }
        }

        public object dissolve_field
        {
            get
            {
                return m_gpParameters[6];
            }
            set
            {
                m_gpParameters[6] = value;
            }
        }

        public string ToolboxDirectory
        {
            get
            {
                return m_ToolboxDirectory;
            }
            set
            {
                m_ToolboxDirectory = value;
            }
        }

        public string ToolboxName => "Analysis Tools.tbx";

        public string ToolName => "Buffer";

        public string Alias => "analysis";

        public object[] ParameterInfo => m_gpParameters;

        public Buffer()
        {
            m_gpParameters = new object[7];
            m_ToolboxDirectory = ResolveDirectory();
        }

        public Buffer(object in_features, object out_feature_class, object buffer_distance_or_field)
        {
            m_gpParameters = new object[7];
            m_ToolboxDirectory = ResolveDirectory();
            this.in_features = in_features;
            this.out_feature_class = out_feature_class;
            this.buffer_distance_or_field = buffer_distance_or_field;
        }

        private string ResolveDirectory()
        {
            string result = "[SYSTEMTOOLBOXLOCATION]";
            Assembly executingAssembly = Assembly.GetExecutingAssembly();
            string text = executingAssembly.Location + ".config";
            FileInfo fileInfo = new FileInfo(text);
            if (fileInfo.Exists)
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(text);
                XmlNode xmlNode = xmlDocument.SelectSingleNode("configuration/toolbox");
                if (xmlNode != null)
                {
                    result = xmlNode.Attributes["directory"].Value;
                }
            }

            return result;
        }
    }
}

有些引數設定比較好理解,例如in_features,可以設定一個shape檔案路徑、IFeatureClass物件、IFeatureLayer物件或者.Lyr檔案路徑等。但為了執行穩定,保險期間,我一般都設定檔案路徑。

out_feature_class引數也比較好理解,設定一個輸出的Shape檔案路徑即可。

後面的line_side、line_end_type、dissolve_option都是字串型別的可選引數,這種一般還比較簡單寫,看幫助中的參數列部分,基本上可以解決我們的問題。

image3.png

還有兩個引數buffer_distance_or_field和dissolve_field,這兩個比較難設定。dissolve_field還好,是一個可選引數,我之前也沒用過,可以先不管。但buffer_distance_or_field引數,看到這個名字就知道這個引數非常重要。按正常理解的話,這個引數應該是一個數位型別的引數,用來設定緩衝距離。我們再看下幫助是如何描述這個引數的。

image4.png

這個欄位可識別的型別有欄位和線性單位,通過描述可以知道,引數可以傳數位+單位以及欄位名稱。如果只傳一個數位,那麼就按照該數位以及資料本身的單位進行緩衝區分析;如果傳數位+單位,就按照傳入的數位和單位進行緩衝區分析;如果傳欄位名稱,就按照該欄位的值進行緩衝區分析。就是說,我們設定數位100、字串」100 Meters」或者一個數位型別的欄位名稱均是可以的。

但如果傳欄位,欄位型別是字串,裡面的值為數位+單位的格式是否識別?或者該引數傳一個IField物件是不是可以識別?再或者欄位是數位型別,我們傳欄位名稱+單位是不是也可以?因為這些在實際應用中,沒有應用過,所以並沒有進行驗證。如果有需要這麼處理的,可以去驗證下。

如果還不知道這個引數如何引數,那麼還有一個更直觀的辦法。先用自己想設定的引數在ArcMap中執行一下。如下圖所示。

image5.png

點選OK按鈕執行,之後後,去Toolbox的Result模組檢視執行的py指令碼。如下圖所示。

image6.png

拷貝後,可以把指令碼放到記事本里。如下圖所示。

image7.png

這樣我們是不是就可以知道buffer_distance_or_field引數要怎麼設定了?dissolve_field引數更復雜,但通過這樣的方法,也可以獲取該引數的設定格式。

3、ArcObject SDK 呼叫Toolbox的技巧

熟練使用ArcToolbox以及會看Toolbox的幫助;

善於能把各類Tool串起來,完成一個完整的業務模組

先用資料在ArcMap的ArcToolbox上做驗證;

Tool設定引數的時候,資料儘量用路徑,路徑儘量不要有漢字、空格等,傳入的引數路徑名稱儘量以字母開頭;

在程式碼中呼叫報錯,用同樣的資料、同樣的引數,在ArcMap裡面去執行一下,一般兩者是沒什麼差別的,在ArcMap找到什麼原因後,再去修改程式碼;

設定引數的時候,結合Arcpy去分析可接受引數的格式。