IDL與C#混合編程技術

轉自:http://blog.sina.com.cn/s/blog_764b1e9d0100w06w.html

 

C# (C Sharp)是微軟公司在20006月發佈的一種新的編程語言。C#Java有很多的相似之處,包括了諸如單一繼承、界面、與Java幾乎同樣的語法,和編譯成中間代碼再運行的過程。它又借鑑了Delphi的一個特點,與COM(組件對象模型)是直接集成的,而且它是微軟公司.NET windows網絡框架的主角。

IDL則一直是應用程序開發和科學家進行可視化與分析的首選語言。因爲它功能強大,簡單易學,很少的幾行代碼就能實現其他語言很難實現的功能,所以它是進行科學數據分析、可視化表達和跨平臺應用開發的高效軟件和理想工具。作爲第四代語法簡單、面向矩陣運算的計算機語言,IDL擁有豐富的分析工具包。同時支持遙感圖像處理軟件ENVI的二次開發,使得利用IDL進行ENVI二次開發實現數據處理分析和可視化程序變得非常容易。

1         C#調用IDL方式

C#可以通過COM組件的方式直接調用IDL進行開發。IDL提供了IDLDrawWidgetCOM_IDL_CONNECT兩個組件,其中IDLDrawWidget組件是帶UI的可視組件,COM_IDL_CONNECT是不帶UI的功能組件,在實際使用的時候可以根據應用需求選取。

IDLDrawWidget組件爲例,該組件包含了多種功能方法(見表1),這些方法使得C#在調用的時候方便進行初始化、功能調用、參數傳遞和事件響應傳遞。

1 IDLDrawWidget組件的方法

方法名稱

功能描述

CopyNamedArray

拷貝IDL下數組到組件調用環境中的變量數組

CopyWindow

IDLDrawWidget組件顯示內容拷貝到Windows剪貼板中

CreateDrawWidget

IDLDrawWidget控件初始化界面

DoExit

退出ActiveX控件並釋放IDL佔用的資源

ExecuteStr

執行IDL命令,相當於IDL的命令行功能

GetNamedData

獲取IDL中變量的值

InitIDL

IDL運行環境初始化(1:成功;0,失敗;-1組件未被許可;-2IDL未安裝許可)

InitIDLEx

IDL運行環境初始化(可傳入參數)

Print

組件中顯示內容輸出到默認打印機

RegisterForEvents

組件是否傳遞程序事件(參考表17.2)

SetNamedArray

基於輸入的變量名和內容在IDL下創建數組

SetNameData

基於輸入的變量名和內容在IDL下創建變量

SetOutputWnd

組件顯示內容輸出到指定窗口

VariableExists

判斷IDL下是否存在此變量

 

2         關鍵技術

以在Visual Studio 2008 C#下調用IDLDrawWidget組件爲例,分析下調用該組件的關鍵技術。

(一)    組件初始化

與其他ActiveX組件一樣,在VisualStudio的工具箱組件上單擊鼠標右鍵,彈出菜單中選擇[選擇項],見圖1

1 加載組件 

彈出的選擇工具箱項界面中點擊TAB界面[COM組件],列表中找到“IDLDrawWidget Control3.0”並勾選(圖2)。若列表中不存在該組件,點擊[瀏覽]查找IDL安裝目錄下的子目錄“bin\bin.x86”中的“idldrawx3.ocx”文件。

 

IDL與C#混合編程技術

2 COM組件列表

組件初始化前需要設置組件的IDL安裝目錄,本機的IDL安裝目錄可以通過查找註冊表選項的方式獲取,獲取IDL8.0安裝路徑的C#示例代碼如下:

//讀取註冊表獲取IDL8.0

RegistryKey rsg = null;

rsg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\ITT\\IDL\\8.0", true);

if (rsg.GetValue("InstallDir") != null) //讀取失敗返回null

{

    //初始化IDL80路徑

    axIDLDrawWidget1.IdlPath = Path.Combine(rsg.GetValue("InstallDir").ToString(), @"IDL80\bin\bin.x86\idl.dll");

}

int n;

  //初始化

  n = axIDLDrawWidget1.InitIDL((int)this.Handle);

  if (n == 0)

  {

     MessageBox.Show("IDL初始化失敗", "IDL初始化失敗,無法繼續!");

      return;

  }

 

(二)    功能調用

IDLDrawWidget組件支持調用IDL的源碼文件和sav文件。其中ExecuteStr方法相當於IDL的命令行,而IDL可以使用點命令(見表2)在命令行下進行源碼的編譯和功能調用。故,通過ExecuteStr方法可以輕鬆地調用IDL功能。

2 點命令(DotCommand

命 令

功 能

.COMPILE

編譯代碼;

.CONTINUE

繼續執行代碼;

.EDIT

在編輯器中打開代碼以便編輯;

.FULL_RESET_SESSION

編譯器完全重置(包括DLM等);

.GO

執行最近編譯過的主函數;

.OUT

執行當前程序直至返回;

.RESET_SESSION

編譯器重置,等同於點擊工具欄的重置

.RETURN

程序返回;

.RENEW

新建一個pro

.RUN

編譯內存中的程序並執行主程序;

.SKIP

跳過程序段;

.STEP

執行1個或n個程序;

.STEPOVER

執行1個程序段,如果程序段中調用了其他函數則調試進入函數;

.TRACE

程序異常時繼續運行。

 

使用點命令在命令行下進行源碼編譯和運行的示例代碼:

IDL>;編譯源碼文件,注意源碼文件路徑是字符串,用’’””

IDL> .compile 'C:\temp\firstIDL.pro'

% Compiled module: MYFUN.

% Compiled module: FIRSTIDL.

% Compiled module: TEST.

IDL>;調用源碼中的pro執行

IDL> firstidl

abc

       9

 

(三)    數據傳遞

IDLDrawWidget組件通過SetNamedArraySetNameData等方法進行數據傳遞(表1),C#IDL之間支持基本的數據類型變量和數組傳遞(表3)。

3 IDLActiveX下的通用的變量類型

IDL類型

ActiveX類型

IDL_TYPE_BYTE

UT_UI1 – unsigned char

IDL_TYPE_BYTE

VT_I1 - signed char

IDL_TYP_INT

VT_I2 - signed short

IDL_TYP_LONG

VT_I4 - signed long

IDL_TYP_FLOAT

VT_R4 - float

IDL_TYP_DOUBLE

VT_R8 - double

傳遞字符串變量和數組的示例代碼如下:

//初始化定義變量

object objStr = "abc";

object objOri,objNow;

//定義變量

this.axIDLDrawWidget1.SetNamedData("var", objStr);

//編譯IDL功能代碼並傳入單個變量

this.axIDLDrawWidget1.ExecuteStr(@".compile 'exchangevar.pro'");

this.axIDLDrawWidget1.ExecuteStr("exchangevar, var = var");

//IDL中修改過的變量獲得並對話框顯示

objStr = this.axIDLDrawWidget1.GetNamedData("var");

//顯示IDL程序中更改後的值

MessageBox.Show("C#中的變量值爲:"+objStr.ToString());

//定義數組

int[,] dataarr = new int[3, 2] { { 6, 4 }, { 12, 9 }, { 18, 5 } };

//將數組內容copyIDL下的變量arr

this.axIDLDrawWidget1.SetNamedArray("arr", dataarr, true);

//編譯IDL功能代碼並傳入數組

this.axIDLDrawWidget1.ExecuteStr(".compile 'exchangeArr.pro'");

this.axIDLDrawWidget1.ExecuteStr("exchangeArr,arr,oriArr= oriArr");

//通過CopyNameArray方法直接複製獲取IDL中的數組

objOri = this.axIDLDrawWidget1.CopyNamedArray("oriarr");

//通過CopyNameArray方法直接複製獲取IDL中的數組

objNow = this.axIDLDrawWidget1.CopyNamedArray("arr");

//彈出第一個元素的值           

MessageBox.Show("C#中的數組值爲:" + ((Array)objNow).GetValue(0, 0));

 

(四)    事件傳遞

IDLDrawWidget組件可以在C#IDL下響應鍵盤和鼠標事件。即通過C#主程序可以觸發組件的事件並由IDL事件響應程序進行響應。組件的事件響應處理方式與組件的RegisterForEvents值有關,各個值的含義見表4

4 RegisterForEvents對應功能描述

功能描述

0

停止傳遞所有事件

1

傳遞鼠標移動事件

2

傳遞鼠標按鍵點擊事件

4

傳遞視圖滾動條事件

8

傳遞暴露事件

 

組件界面中添加鼠標滾輪事件的示例代碼如下:

public Form1()

{

    InitializeComponent();

    //增加滾輪滾動事件

    ((Control)this).MouseWheel += new MouseEventHandler(Form1_MouseWheel);

}

 

private void IDLDrawWidgetCreate()

{

    //指定事件由C#響應

    axIDLDrawWidget1.RegisterForEvents(3);

}

//鼠標滾輪事件

void Form1_MouseWheel(object sender, MouseEventArgs e)

{

//轉換當前鼠標點在組件上的位置

   y = axIDLDrawWidget1.Height - (e.Y - axIDLDrawWidget1.Location.Y);           

//調用IDL的鼠標時間代碼

   axIDLDrawWidget1.ExecuteStr("oImg.WheelEvents," + e.Delta.ToString() + ","+ (e.X - axIDLDrawWidget1.Location.X).ToString() + "," + y.ToString());

}

IDL中的響應該事件的代碼如下:

;鼠標滾輪時的事件

PRO ImgSHow::WheelEvents,wType,xPos,yPos

  COMPILE_OPT idl2

   ;獲取組件原始大小

  self.OWINDOW.GETPROPERTY, dimensions = winDims,graphics_tree = oView

  oView.GETPROPERTY, viewPlane_Rect = viewRect 

  ;判斷是放大還是縮小

  IF wType GT 0 THEN rate = 0.8 ELSE rate = 1.125

   ;計算放縮後的顯示區域大小

  oriDis =[xPos,yPos]*viewRect[2:3]/winDims

  viewRect[0:1]+=(1-rate)*oriDis

  viewRect[2:3]= viewRect[2:3]*rate

  ;更新顯示區域並重新渲染繪製

  oView.SETPROPERTY, viewPlane_Rect = viewRect

  self.OWINDOW.DRAW

END

類似的方式可以添加鼠標拉框放大和縮小等功能,即通過C#IDLDrawWidget組件構建了一個完整的圖像顯示與基本處理程序,通過鼠標可以對顯示圖像進行放大、縮小和平移操作,並通過IDL實現了基本的圖像處理、投影變換和仿真模擬功能。部分效果圖:

 

IDL與C#混合編程技術  

3 靈活的操控

           IDL與C#混合編程技術 

4 圖像顯示與圖像處理

   IDL與C#混合編程技術
5 投影變換功能 

IDL與C#混合編程技術                  6 衛星仿真模擬

3         結束語

通過IDLDrawWidget等組件提供的方法,C#可以方便靈活地集成IDL程序,輕鬆搭建可視化分析與處理系統的框架,快速集成IDL的可視化分析與處理功能。這樣充分發揮各語言的優勢,構建複雜的可視化應用與分析的系統將會變得非常方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章