本文介绍如何使用程序完成对象选取的功能。

Toolkit中使用ProSelection记录Creo运行过程中选择的对象。ProSelect是一个高频使用的选择对象函数,但是需要用户自己操作选择,显然无法胜任自动化或者批处理相关工作的要求。所幸Toolkit还提供了ProSelbufferClearProSelbufferSelectionAdd函数用于清空和添加会话中的ProSelection,使得使用程序完成对象选取变得可能。

1.函数说明

ProSelbufferClear清空当前Creo会话中所选的对象,使用非常简单,没有参数:

1
status = ProSelbufferClear();

ProSelbufferSelectionAdd可以用过程序的方式将对象添加到会话选择的对象中,其参数为对应的ProSelection对象:

1
status = ProSelbufferSelectionAdd(selection);

通常来说我们需要选取的特征(装配体中组件)以ProModelitem类型进行保存,Toolkit提供了ProSelectionAlloc函数完成了从ProModelitemProSelection的转换。该函数有三个参数,第一个参数 ProAsmcomppath* p_cmp_path仅对装配体中组件中需要指定,对应组件装配树路径,第二个参数ProModelitem* p_mdl_itm为需要转换的ProModelitem对象,第三个参数 ProSelection* p_selection对应转换得到的ProSelection对象,示例代码如下:

1
2
3
4
//零件状态下使用
status = ProSelectionAlloc(NULL, &feature, &selection);
//装配体下必须指定装配树路径
status = ProSelectionAlloc(&asmcomppath, &component, &selection);

2.选择零件的特征

选择零件的特征必须要获得其对应的ProModelitem对象。本文作为测试,以选定所有的坐标系特征为例,首选通过ProSolidFeatVisit获取所有坐标系特征:

1
2
3
4
5
6
7
8
9
ProError status;
ProMdl mdl;
ProSelection selection;
ProFeature *p_features;
int i, n_size;

status = ProMdlCurrentGet(&mdl);
status = ProArrayAlloc(0, sizeof(ProFeature), 1, (ProArray *)&p_features);
status = ProSolidFeatVisit((ProSolid)mdl, (ProFeatureVisitAction)FeatVisitActFn, FeatVisitFilter, (ProAppData)&p_features);

ProSolidFeatVisit对应的过滤函数和动作函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ProError FeatVisitActFn(ProFeature *p_feature, ProError status, ProAppData p_features)
{
ProBoolean isVisible;
ProFeatStatus p_status;
ProModelitem modelitem;

status = ProFeatureStatusGet(p_feature, &p_status);
status = ProFeatureVisibilityGet(p_feature, &isVisible);
if (isVisible == PRO_B_TRUE && p_status != PRO_FEAT_SUPPRESSED)
{
status = ProArrayObjectAdd((ProArray *)p_features, PRO_VALUE_UNUSED, 1, p_feature);
}
return PRO_TK_NO_ERROR;
}

ProError FeatVisitFilter(ProFeature *feature, ProAppData app_data)
{
ProError status;
ProFeattype ftype;
status = ProFeatureTypeGet(feature, &ftype);
if (ftype == PRO_FEAT_CSYS)
return PRO_TK_NO_ERROR;
return PRO_TK_CONTINUE;
}

所获取的坐标系特征ProFeature均保存在p_feature数组中,对其进行遍历,使用ProSelectionAlloc创建ProSelection对象并使用ProSelbufferSelectionAdd完成将坐标系对象添加到会话选择中:

1
2
3
4
5
6
status = ProArraySizeGet(p_features, &n_size);
for (i = 0; i < n_size; i++)
{
status = ProSelectionAlloc(NULL, &(p_features[i]), &selection);
status = ProSelbufferSelectionAdd(selection);
}

使用程序选中所有坐标系特征如图1所示:

图1 使用程序选中所有坐标系特征

3.选择装配体的组件

选择装配体的组件ProAsmcomp相对选择零件的特征ProFeature复杂,体现在构造ProSelectionProSelectionAlloc需要指定其装配树路径ProAsmcomppathProAsmcomppath在官方文档描述如下:

The object ProAsmcomppath is one of the main ingredients in the ProSelection object, as described in The Selection Object.

所以比较遗憾,直接从组件ProAsmcomp获取其ProAsmcomppath只能使用ProSelect或者访问Selbuffe中的ProSelection,而这之前都是需要人工手动操作完成,与使用程序选中对象的操作明显相违背。

幸好Toolkit提供了ProSolidDispCompVisit用于遍历装备体已显示组件并可获取其ProAsmcomppath,因此配合ProSolidFeatVisit遍历装备体组件获取其ProAsmcomp,通过查找定位两者信息,即可完成ProSelectionAlloc参数的获取。

首先给出ProSolidFeatVisit遍历记录装配树所有已显示节点ProAsmcomp的代码,其对应的过滤函数和动作函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ProError AsmCompVisitFilter(ProFeature *feature, ProAppData app_data)
{
ProError status;
ProFeattype ftype;
status = ProFeatureTypeGet(feature, &ftype);
if (ftype == PRO_FEAT_COMPONENT)
return PRO_TK_NO_ERROR;
return PRO_TK_CONTINUE;
}

ProError AsmCompVisitActFn(ProFeature *p_comp, ProError status, void *p_comps)
{
ProBoolean isVisible;
ProFeatStatus p_status;
ProMdl mdl;
ProModelitem modelitem;

status = ProFeatureStatusGet(p_comp, &p_status);
status = ProFeatureVisibilityGet(p_comp, &isVisible);
if (isVisible == PRO_B_TRUE && p_status != PRO_FEAT_SUPPRESSED)
{
status = ProArrayObjectAdd((ProArray *)p_comps, PRO_VALUE_UNUSED, 1, p_comp);
status = ProAsmcompMdlGet((ProAsmcomp *)(p_comp), (ProMdl *)&mdl);
status = ProMdlToModelitem(mdl, &modelitem);
if (modelitem.type == PRO_ASSEMBLY)
{
status = ProSolidFeatVisit((ProSolid)mdl, (ProFeatureVisitAction)AsmCompVisitActFn, AsmCompVisitFilter, p_comps);
}
}
return PRO_TK_NO_ERROR;
}

所获取的组件特征ProAsmcomp均保存在p_comps数组中:

1
2
3
status = ProArrayAlloc(0, sizeof(ProModelitem), 1, (ProArray *)&p_comps);
status = ProSolidFeatVisit((ProSolid)mdl, (ProFeatureVisitAction)AsmCompVisitActFn, AsmCompVisitFilter, (ProAppData)&p_comps);
status = ProArraySizeGet(p_comps, &n_compsize);

ProSolidDispCompVisit遍历记录装配树所有已显示节点ProAsmcomppath过滤函数这里默认访问所有节点,过滤函数可以设为NULL或者默认返回所有节点:

1
2
3
4
5
ProError AsmCompPathVisitFilter(ProAsmcomppath *p_path, ProSolid solid, ProAppData app_data)
{
// 这里遍历,所以没有filter
return PRO_TK_NO_ERROR;
}

ProSolidDispCompVisit访问函数比ProSolidFeatVisit稍显复杂,多了的第三个参数ProBoolean down官方解释如下:

Use PRO_B_TRUE when going down to this component and PRO_B_FALSE when going up from this component.

实际测试下,在遍历对应的子装配节点,会同时访问按照装配树访问其父节点和子节点,当该参数为PRO_B_TRUE时访问子节点,PRO_B_FALSE则访问其父节点,两个操作依次进行,如果全部记录会造成数据混乱。另外访问函数是直接遍历所有节点,不需要像ProSolidFeatVisit那样使用递归的方式访问子装配体的节点。故我们在此进行过滤,只访问向下的子节点,访问函数代码如下:

1
2
3
4
5
6
7
8
9
10
ProError AsmCompPathVisitActFn(ProAsmcomppath *path, ProSolid solid, ProBoolean down, ProAppData p_comppaths)
{
ProError status;
// ProSolidDispCompVisit同时往up和down两个方向检索,所以只看down方向,up方向跳过
if (down == PRO_B_TRUE)
{
status = ProArrayObjectAdd((ProArray *)p_comppaths, PRO_VALUE_UNUSED, 1, path);
}
return PRO_TK_NO_ERROR;
}

所获取的组件特征ProAsmcomppath均保存在p_comppaths数组中:

1
2
3
status = ProArrayAlloc(0, sizeof(ProAsmcomppath), 1, (ProArray *)&p_comppaths);
status = ProSolidDispCompVisit((ProSolid)mdl, AsmCompPathVisitActFn, AsmCompPathVisitFilter, (ProAppData)&p_comppaths);
status = ProArraySizeGet(p_comppaths, &n_pathsize);

对比发现,两个数组长度不同,p_comppaths长度比p_comps长度多1,原因在于p_comppaths还记录了最上层装配体根节点。实际代码编写中发现,ProSelectionAlloc第一个参数是p_comps父节点的ProAsmcomppath而非其本身,所以p_comppaths数组第一个记录的根节点很重要不能删除。另外ProSelectionAlloc前两个参数如果不对应会返回PRO_TK_BAD_INPUTS,如果此时执行ProSelbufferSelectionAdd会导致Creo异常退出。在实际操作时,可以定义一个记录装配体树形结构数据结构同时保存节点位置和其对应的p_comppathsp_comps以便完成选取对应的组件功能。本文仅做测试,没有记录p_comppathsp_comps的对应关系,故使用双循环遍历后判断添加,效率很低,仅做演示,作为全选的功能够用了:

1
2
3
4
5
6
7
8
9
for (j = 0; j < n_pathsize; j++)
{
for (i = 0; i < n_compsize; i++)
{
status = ProSelectionAlloc(&(p_comppaths[j]), &(p_comps[i]), &selection);
if (status == PRO_TK_NO_ERROR)
status = ProSelbufferSelectionAdd(selection);
}
}

使用程序选中所有组件如图2所示:

图2 使用程序选中所有组件

完整代码可在Github.com下载。代码在VS2010,Creo 2.0 M060 X64下编译通过。