1. 程式人生 > >Pro/TOOLKIT示例程式(二)遍歷模型下的所有特徵

Pro/TOOLKIT示例程式(二)遍歷模型下的所有特徵

特徵的基本概念

Pro/E是基於特徵的引數化造型系統,在模型樹上的每個專案都是特徵。如下圖所示:
這裡寫圖片描述
該檔案有3個基準面、1個座標系、1個拉伸、1個孔共6個特徵。
我們可以通過配置【樹列】選項來檢視特徵的資訊。
這裡寫圖片描述
這裡寫圖片描述
特徵是對Pro/E模型中幾何元素的一層封裝。就好比你是負責指揮戰爭的司令官,你只會下達這樣的命令:X師、Y師去攻打敵軍的哪個部隊,而不會詳細到X師、Y師下的具體成員。特徵就類似於師的概念,而師下面的每個戰士就相當於是幾何元素。
因此,我們可以遍歷特徵下的所有幾何元素,Pro/TOOLKIT提供了這樣的API:ProFeatureGeomitemVisit()。
特徵的定義如下:

typedef struct pro_model_item
{
  ProType  type;
  int      id;
  ProMdl owner;
}ProFeature;

它和ProModelitem共用相同的資料結構。其中

  • type:值為PRO_FEATURE。
  • id:特徵ID。
  • owner:特徵所屬的模型。

示例

程式碼如下:

// 實體模型特徵訪問函式
ProError SolidFeatVisitFunc(ProFeature* p_feature,
                            ProError status,
                            ProAppData app_data)
{
    ProArrayObjectAdd((ProArray*)app_data, -1
, 1, p_feature); return PRO_TK_NO_ERROR; } // 命令響應函式:遍歷訪問實體檔案中的特徵 int VisitSolidFeats(uiCmdCmdId command, uiCmdValue *p_value, void *p_push_command_data) { ProError err; // 獲取當前模型 ProMdl mdlCurr; err = ProMdlCurrentGet(&mdlCurr); if
(PRO_TK_NO_ERROR != err) { return -1; } // 定義陣列存放特徵 ProFeature* featArr; err = ProArrayAlloc(0, sizeof(ProFeature), 5, (ProArray*)&featArr); // 遍歷訪問模型下的所有特徵 err = ProSolidFeatVisit((ProSolid)mdlCurr, SolidFeatVisitFunc, NULL, &featArr); // 輸出所有特徵的資訊 int nSize = 0; err = ProArraySizeGet(featArr, &nSize); CStringW cstrSize; cstrSize.Format(L"當前模型共有%d個特徵", nSize); MessageBoxW(NULL, cstrSize, L"icaxdev: Sample002", MB_OK); for (int i = 0; i < nSize; ++i) { ProName featName; ProModelitemNameGet(&(featArr[i]), featName); CStringW cstrFeatInfo; cstrFeatInfo.Format(L"特徵名稱為:%s; 特徵ID為:%d", featName, featArr[i].id); MessageBoxW(NULL, cstrFeatInfo, L"icaxdev: Sample002", MB_OK); } // 釋放陣列空間 err = ProArrayFree((ProArray*)&featArr); return 0; }

程式碼說明

ProArray

ProArray是Pro/TOOLKIT中的動態陣列,一般的使用步驟如下:
1. 初始化陣列:ProArrayAlloc。
2. 往陣列中新增或刪除元素:ProArrayObjectAdd、ProArrayObjectRemove。
3. 使用完後釋放陣列空間:ProArrayFree。

ProArrayAlloc:初始化陣列,為陣列分配記憶體空間。
ProError ProArrayAlloc(
  int n_objs,
    int obj_size,
    int reallocation_size,
    ProArray* p_array);
  • n_objs:陣列的初始大小。一般傳0即可。
  • obj_size:陣列元素的大小(單位為位元組),一般傳sizeof(元素型別)。比如陣列存放的元素型別為int,傳sizeof(int)即可。sizeof操作符會計算出型別佔用的位元組數。
  • reallocation_size:當陣列空間大小發生變化時,每次遞增或遞減的大小。如果你沒有深入理解ProArray的記憶體實現,一般可以傳5這個經驗值。
  • p_array:陣列變數的地址。
ProArrayObjectAdd:往陣列中新增元素。
ProError ProArrayObjectAdd(
  ProArray* p_array,
    int       index,
    int       n_objects,
    void*     p_object);
  • p_array:陣列的地址。
  • index:在何處新增元素,一般傳-1,表明在陣列最後新增元素。
  • n_objects:新增元素的數量。
  • p_object:要新增元素的地址。
ProArraySizeGet:獲取陣列的大小。
ProError ProArraySizeGet(
  ProArray array,
    int*     p_size);
  • array:陣列。
  • p_size:接收陣列大小變數的地址。
ProArrayFree:釋放陣列記憶體空間。
ProError ProArrayFree(ProArray* p_array);
  • p_array:陣列的地址。

過濾函式和訪問函式

在Pro/TOOLKIT中,如果你想遍歷某個物件下的所有子物件,比如遍歷實體檔案下的所有特徵,遍歷特徵下的所有面等等,需要用到過濾函式和訪問函式。過濾函式和訪問函式的原型已由Pro/TOOLKIT指定,你需要定義出它們具體的實現,然後將函式指標傳遞給對應的API。則父物件下的所有子物件都會依次被過濾函式和訪問函式呼叫。如下圖所示:
這裡寫圖片描述
過濾函式就像一個漏斗,其返回值可以決定子物件是否繼續被訪問函式呼叫,當其返回值為PRO_TK_CONTINUE時,則不會被訪問函式呼叫。當你只想訪問某個物件下的子物件的一個子集時,過濾函式會派上用場。
下面我們以遍歷實體模型下的所有特徵為例來講解過濾函式和訪問函式。

ProSolidFeatVisit

ProSolidFeatVisit用於訪問實體檔案中的所有特徵。

ProError ProSolidFeatVisit(
  ProSolid               p_handle,
    ProFeatureVisitAction  visit_action,
    ProFeatureFilterAction filter_action,
    ProAppData             app_data);
  • p_handle:實體模型。
  • visit_action:訪問函式指標。
  • filter_action:過濾函式指標。
  • app_data:傳遞給訪問函式和過濾函式的資料。
訪問函式的原型:
typedef ProError (*ProFeatureVisitAction)(ProFeature* p_feature,
                                          ProError status,
                                          ProAppData app_data);
  • p_feature:被訪問特徵的指標。
  • status:狀態值,很少使用。
  • app_data:ProSolidFeatVisit傳遞過來的資料(ProSolidFeatVisit的最後一個引數)。對於本示例程式而言,即為特徵陣列的指標:&featArr。

在示例程式中,我們定義了訪問函式SolidFeatVisitFunc,將被訪問的特徵新增到陣列。

過濾函式的原型:
typedef ProError (*ProFeatureFilterAction)(ProFeature* p_feature,
                                           ProAppData app_data);
  • p_feature:被訪問特徵的指標。
  • app_data:ProSolidFeatVisit傳遞過來的資料(ProSolidFeatVisit的最後一個引數)。對於本示例程式而言,即為特徵陣列的指標:&featArr。
  • 返回值:當返回值為PRO_TK_CONTINUE時,則當前p_feature指向的特徵不會經過訪問函式。當返回值為其它值時,返回值被傳遞給訪問函式的第二個引數ProError status。

在示例程式中,我們沒有定義過濾函式,直接傳NULL。

擴充套件知識

強烈推薦使用C++標準模板庫(STL)中的vector、list來替代ProArray。因為vector、list本身負責記憶體空間的分配與釋放,並且使用起來也更方便友善。而使用ProArray的話,你需要手動申請與手動釋放記憶體空間,使用不好很容易出錯。
本次示例程式,使用vector替代ProArray的程式碼如下:

// 實體模型特徵訪問函式
ProError SolidFeatVisitFunc(ProFeature* p_feature,
                            ProError status,
                            ProAppData app_data)
{
    vector<ProFeature>* pFeatVec = (vector<ProFeature>*)app_data;
    pFeatVec->push_back(*p_feature);
    return PRO_TK_NO_ERROR;
}

// 命令響應函式:遍歷訪問實體檔案中的特徵
int VisitSolidFeats(uiCmdCmdId  command,
                    uiCmdValue *p_value,
                    void       *p_push_command_data)
{
    ProError err;

    // 獲取當前模型
    ProMdl mdlCurr;
    err = ProMdlCurrentGet(&mdlCurr);
    if (PRO_TK_NO_ERROR != err)
    {
        return -1;
    }

    // 遍歷訪問模型下的所有特徵
    vector<ProFeature> vecFeat;
    err = ProSolidFeatVisit((ProSolid)mdlCurr, SolidFeatVisitFunc, NULL, &vecFeat);

    // 輸出所有特徵的資訊
    CStringW cstrSize;
    cstrSize.Format(L"當前模型共有%d個特徵", vecFeat.size());
    MessageBoxW(NULL, cstrSize, L"icaxdev: Sample002", MB_OK);

    vector<ProFeature>::iterator iterFeat = vecFeat.begin();
    for (; iterFeat != vecFeat.end(); ++iterFeat)
    {
        ProName featName;
        ProModelitemNameGet(&(*iterFeat), featName);
        CStringW cstrFeatInfo;
        cstrFeatInfo.Format(L"特徵名稱為:%s; 特徵ID為:%d", featName, iterFeat->id);
        MessageBoxW(NULL, cstrFeatInfo, L"icaxdev: Sample002", MB_OK);
    }

    return 0;
}