C#調用GDAL算法進度信息傳遞

GDAL庫中提供了很多的算法,同時也提供了進度條的參數。對於C++調用來說,應該沒什麼問題,但是對C#調用來說,在進度條這塊需要寫一個代理來進行傳遞。首先寫一個簡單的測試代碼。

首先定義一個委託函數原型,需要與GDAL庫中的C#進度條接口保持一致,一個簡單的原型如下。

    /// <summary>
    /// 進度信息回調函數
    /// </summary>
    /// <param name="dfComplete">完成比例,0~1之間的數</param>
    /// <param name="pszMessage">進度條信息</param>
    /// <param name="pProgressArg">進度條用戶數據</param>
    /// <returns></returns>
    public delegate int ProgressFunc(double dfComplete, char[] pszMessage, IntPtr pProgressArg);
接下來在自己的測試代碼中編寫一個進度條函數,爲了方便,先編寫一個控制檯的,直接從GDAL庫中提供的控制檯進度條修改而成,進度條函數代碼如下。具體可以參考GDAL庫中的控制檯進度條實現代碼,幾乎完全一樣,除了將printf函數改成了Console.Write,別的沒有啥區別。

    class GDALAlgCsTest
    {
        //進度信息回調函數
        static int nLastTick = -1;
        public int TermProgress(double dfComplete, char[] strMessage, IntPtr Data)
        {
	        int nThisTick = (int) (dfComplete * 40.0);

	        nThisTick = Math.Min(40, Math.Max(0, nThisTick));

	        // Have we started a new progress run?
	        if( nThisTick < nLastTick && nLastTick >= 39 )
		        nLastTick = -1;

	        if( nThisTick <= nLastTick )
		        return 1;

	        while( nThisTick > nLastTick )
	        {
		        nLastTick++;
		        if( nLastTick % 4 == 0 )
                    Console.Write("{0}", (nLastTick / 4) * 10);
		        else
                    Console.Write(".");
            }

	        if( nThisTick == 40 )
                 Console.Write( " - done.\n");
	        else
                Console.Write("");

            return 1;
        }
}
接下來就是在測試代碼中進行調用了。下面是我將GDAL庫的算法進行了封裝,不過進度條的接口與GDAL庫中的算法進度條接口一模一樣,我封裝了一個波段合併的算法,就是將好幾個單波段文件合併爲一個多波段文件,主要是用來將Landsat衛星下載的分波段存儲的數據進行合併形成一個多波段的數據。函數的接口聲明如下:

        /// <summary>
        /// 圖像波段合併
        /// </summary>
        /// <param name="astrSrcFileList">輸入文件列表,所有的輸入路徑中間使用*號進行分割</param>
        /// <param name="strDstFile">輸出文件路徑</param>
        /// <param name="iDataType">柵格數據的數據類型(參考GDALDataType)</param>
        /// <param name="bUnion">範圍不一致的圖像處理方式,true爲求並,false爲求交</param>
        /// <param name="strFormat">輸出文件格式,詳細參考GDAL支持數據類型</param>
        /// <param name="pFun">進度條回調函數</param>
        /// <param name="pUserData">進度條指針</param>
        /// <returns>返回值,表示計算過程中出現的各種錯誤信息</returns>
        [DllImport("GDALAlg", EntryPoint = "ImageLayerStack")]
        public static extern int ImageLayerStack(char[] astrSrcFileList, char[] strDstFile, int iDataType,
            bool bUnion, string strFormat, ProgressFunc pFun, IntPtr pUserData);
最後兩個參數就是進度條參數,倒數第二個爲進度條回調函數(C#裏面的委託函數),倒數第一個參數爲進度條所需的參數信息。具體請參考我之前的進度條相關的博客。上面的函數實現此處不再進行說明,也不是本文的重點。下面就看看怎麼調用這個函數並將進度條傳入。

using System;
using GdalAlg;
using System.Collections;
using System.IO;
using System.Text;

namespace GDALAlgCS
{
    class GDALAlgCsTest
    {
        //進度信息回調函數
        static int nLastTick = -1;
        public int TermProgress1(double dfComplete, char[] strMessage, IntPtr Data)
        {
	        int nThisTick = (int) (dfComplete * 40.0);

	        nThisTick = Math.Min(40, Math.Max(0, nThisTick));

	        // Have we started a new progress run?
	        if( nThisTick < nLastTick && nLastTick >= 39 )
		        nLastTick = -1;

	        if( nThisTick <= nLastTick )
		        return 1;

	        while( nThisTick > nLastTick )
	        {
		        nLastTick++;
		        if( nLastTick % 4 == 0 )
                    Console.Write("{0}", (nLastTick / 4) * 10);
		        else
                    Console.Write(".");
            }

	        if( nThisTick == 40 )
                 Console.Write( " - done.\n");
	        else
                Console.Write("");

            return 1;
        }

        static void Main(string[] args)
        {
            //聲明進度信息回調函數
            ProgressFunc pd = new ProgressFunc(new GDALAlgCsTest().TermProgress1);
            IntPtr p = new IntPtr(0);
            int ire = 0;


            string strLandsat1 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B1.TIF";
            string strLandsat2 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B2.TIF";
            string strLandsat3 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B3.TIF";
            string strLandsat4 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B4.TIF";
            string strLandsat5 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B5.TIF";
            string strLandsat6 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B6.TIF";
            string strLandsat7 = @"F:\Data\LandSat\LT51230322011159IKR00\LT51230322011159IKR00_B7.TIF";

            string strInfiles = strLandsat1 + "*" + strLandsat2 + "*" + strLandsat3 + "*" + strLandsat4 + "*" + strLandsat5 + "*" + strLandsat6 + "*" + strLandsat7;
            string strChineseOut = @"F:\Data\LandSat\LT51230322011159IKR00.tif";

            ire = GdalAlgInterface.ImageLayerStack(strInfiles.ToCharArray(), strChineseOut.ToCharArray(), 0, false, "GTiff", pd, p);

            Console.Write(ire.ToString());
        }
    }
}
上面程序運行中進度效果如下圖所示。

上面的是控制檯的,那麼在圖形界面中如何編寫呢。接下來就寫一個圖形界面的進度條。聲明代理函數都一樣,只不過就是自己需要根據各自界面的進度條控件編寫對應的進度函數。也就是上面類似的TermProgress1函數。首先做一個簡單的界面,如下圖所示。

首先看這個界面的進度條實現函數。在該Form類中定義一個進度條類,具體代碼如下:

        public class Progress
        {
            public int ProgressBarInfo(double dfComplete, char[] strMessage, IntPtr pData)
            {
                GDALForm form = (GDALForm)Control.FromHandle(pData);

                int iValue = (int)(100 * dfComplete + 0.5);
                form.progressBar.Value = iValue;
                string strMsg = new string(strMessage);
                form.labelMessage.Text = strMsg;
                return 1;
            }
        }
首先對函數ProgressBarInfo的參數進行說明,dfComplete是進度信息,0~1之間的小數,strMessage是進度信息,主要是一些說明文字,最後一個pData是用戶自定義的結構信息,這裏的pData就是整個Form的handle。這樣就可以從這個Form的handle中轉換爲界面類的一個對象,並從中獲取進度條控件,然後將進度信息設置給進度條控件,將Message設置給界面的一個Label。

下面再看看函數調用。

        private void buttonOK_Click(object sender, EventArgs e)
        {
            try
            {
                int iRev = 0;
                string strInput = textBoxInput.Text;
                string strOutput = textBoxOutput.Text;
                string strField = "OBJECTID";

                ProgressFunc pd = new ProgressFunc(new Progress().ProgressBarInfo);
                IntPtr pre = this.Handle;
                iRev = GdalAlgInterface.ShpRasterize(strInput.ToCharArray(), strOutput.ToCharArray(), 10, 1, 0, strField.ToCharArray(), "GTiff", pd, pre);
                MessageBox.Show("處理返回代碼:" + iRev.ToString(), "提示");
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.ToString(), "提示");
            }
        }
在點擊【計算】按鈕之後,先獲取輸入和輸出的文件路徑,然後聲明一個委託,用戶定義的結構信息給當前form的handle。然後將委託函數和handle傳入算法函數即可。程序運行的截圖如下所示。該算法爲矢量柵格化的一個封裝函數。

上面的兩個截圖和界面設計截圖有點不一致,主要是將矢量柵格化的幾個參數可以由界面進行設置。上面的代碼中這幾個參數都是在代碼中設置死的。其他的都一樣,對於進度條這塊沒有任何變動。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章