1 前言
目前NX系列CAX系统已经发展成为世界领先的产品设计解决方案,在对一个产品进行开发的过程中,它能提供给工程人员极为丰富的功能。NX Open更是提供了一个开放的二次开发架构,可以让用户方便的将各种应用软件集成到NX中去,为NX的集成和定制提供了一个优秀的平台。目前有大量的企业使用NX的二次开发工具开发为自己量身定做的系统,其中有很多系统已经成为企业的核心技术,极大的提高了企业的市场竞争力并取得了良好的经济效益。本文介绍了在NX Open开发的过程中,结合XML技术,实现了对装配件的装配树结构的抽取,对装配数据的抽取以及将抽取的数据保存为外部XML文件。
2 NX的二次开发工具
NX的二次开发工具发展到今天,已经具有相当的规模,它主要包含NX Open for C/C++、NX Open for Java、NX Open for .NET和NX Open for GRIP。其中NX Open for GRIP由于过于古老,目前已经淘汰;使用NX Open for Java做出的程序可以方便的实现跨平台的应用,但效率不高;NX Open for .NET允许用户选择自己喜欢的语言来编写程序,并提供了相当丰富的类库,但需要.NET Framework的支持。NX Open for C/C++的效率最高,灵活性最好,能够方面的与外部应用进行集成。NX Open for C/C++有两个版本,一个是早期的UG Open C/C++,不过对目前NX的最新功能缺乏支持;另一个是NX Open C++,它设计合理,提高了软件编写工作的效率,但是目前NX Open C++工具还未完成。本文选用UG Open C结合NX Open C++来讨论装配件的数据抽取。
3 XML
XML是标准通用标记语言(Standard Generalized Markup Language)的子集,但他克服了SGML描述信息的复杂性以及SGML文档在网络上传输的庞大性。XML也克服了超文本标记语言(HTML)描述信息的不易扩充性,并继承了SGML的与系统无关性和平台独立性,且具有HTML的简单性。XML能够结构化地描述信息,具有很清楚的信息表达能力。本文采用微软公司的MSXML4作为讨论对象。
4 抽取装配数据
4.1 抽取装配结构
NX所产生的装配数据是一个树形结构,NX Open for C/C++提供了获取装配树根结点的功能和获取子结点的功能。
4.1.1 获取根结点
函数原型:
extern tag_t UF_ASSEM_ask_root_part_occ (tag_t part );
说明:
输入参数“part”是部件的部件Tag,输出为根结点的事例例Tag。
例:
tag_t tagRootPart = NULL_TAG; // 根PART
/* 获取当前装配文件*/
tagCurrentPart = UF_PART_ask_display_part();
if ( NULL_TAG == tagCurrentPart )
{
uc1601( "当前没有任何文件可供操作!", 1 );
return;https://www.ttplay8.cn
}
tagRootPart = UF_ASSEM_ask_root_part_occ( tagCurrentPart );
if ( NULL_TAG == tagRootPart )
{
uc1601 ( "没找到根结点!", 1 );
return;
}
4.1.2 获取子结点
函数原型:
extern int UF_ASSEM_ask_part_occ_children (tag_t part_occur, tag_t ** child_part_occs );
说明:
part_occur是输入参数,指定部件的事例Tag;
*child_part_occs是一个指针,以双重指针的形式传入函数,函数执行完毕后指向一个部件事例Tag的数组,使用完毕后要手工释放掉数组的内存空间;
函数返回值:指示子组件的数量(事例Tag数组长度)。
例:
int iChildCount = -1;
tag_t* Children = NULL;
iChildCount = UF_ASSEM_ask_part_occ_children( tagRootPart, &Children );
4.1.3 获取整个装配树
首先取得根结点,然后采用一个递归算法,就可以遍历整个装配树。
例:
void GenTree( tag_t AssRoot )
{
int iChildCount = -1;
tag_t* Children = NULL;
iChildCount = UF_ASSEM_ask_part_occ_children( AssRoot, &Children ); if ( iChildCount > 0 )
{
for ( int i = 0; i < iChildCount; i++ )
{
// 对拿到的子组件事例进行处理
// ...
GenTree( *( Children + i ) );
}
}
return;
}
4.2 在二次开发中添加对XML的支持
如果要使NX二次开发的工具支持XML,首先要判断自己的系统是否支持微软的MSXML4,如果不支持则需要下载微软的MSXML4软件包进行安装。
在程序中可以通过如下方法来添加对XML的支持:
1 添加对XML文件的引用
在程序声明部分加入对DLL文件的引用:
#import <msxml4.dll>
using namespace MSXML2;
2 在程序中添加对COM的支持
在进行XML操作之前,需要初始化DOM环境:
if ( FAILED( CoInitialize( NULL ) ) )
return;
在XML操作结束之后,要终止COM环境:
CoUninitialize( );
3 处理XML文件
在对一个XML文件进行处理之前,要创建一个COM对象:
HRESULT hr = E_UNEXPECTED;
MSXML2::IXMLDOMDocumentPtr DomDocPtr;
hr = DomDocPtr.CreateInstance( __uuidof( DOMDocument40 ) );
if ( FAILED( hr ) )
{
AfxMessageBox( "创建COM对象实例失败!", MB_OK | MB_ICONERROR );
return;
}
DomDocPtr->async = VARIANT_FALSE;
当上述初始化工作结束之后,便可以进行XML操作了:
IXMLDOMDocumentPtr可以进行对XML文件有关的操作;
IXMLDOMNodePtr可以进行对XML结点有关的操作;
IXMLDOMElementPtr可以进行对XML元素有关的操作;
5 应用实例
本例在已经打开一个装配件的前提下,将整个装配树遍历出来,取得每个子组件的文件名,以装配树的形式存储在一个XML文件里面,默认的XML文件名为“d:\\file.xml”。
本例程序的核心部分如下:
extern "C" DllExport void ufusr ( char *param, int *retcod, int parm_len )
{
/* 系统初始化 */
if ( UF_initialize( ) )
{
// 初始化UF环境
uc1601 ( "UF_initialize( )失败!", 1 );
return;
}
// 初始化COM环境
if ( FAILED( CoInitialize( NULL ) ) )
{
uc1601 ( "CoInitialize( )失败!", 1 );
return;https://www.wan128.cn
}
// 创建COM对象实例
HRESULT hr = E_UNEXPECTED;
MSXML2::IXMLDOMDocumentPtr DomDocPtr;
hr = DomDocPtr.CreateInstance( __uuidof( DOMDocument40 ) );
if ( FAILED( hr ) )
{
uc1601 ( "创建COM对象实例失败!", 1 );
CoUninitialize();
return;
}
DomDocPtr->async = VARIANT_FALSE;
tag_t tagCurrentPart = NULL_TAG; // 当前PART
tag_t tagRootPart = NULL_TAG; // 根PART
char szBuffer[ 512 ]; // 缓冲区512字节
/* 获取当前装配文件 */
tagCurrentPart = UF_PART_ask_display_part();
if ( NULL_TAG == tagCurrentPart )
{
uc1601 ( "当前没有任何文件可供操作!", 1 );
return;
}
tagRootPart = UF_ASSEM_ask_root_part_occ( tagCurrentPart );
if ( NULL_TAG == tagRootPart )
{
uc1601 ( "没找到根结点!", 1 );
return;
}
UF_PART_ask_part_name( tagCurrentPart, szBuffer );
ProcFilename( szBuffer );
_bstr_t bstrName;
bstrName = szBuffer;
MSXML2::IXMLDOMElementPtr DomRoot = NULL_TAG;
DomRoot = DomDocPtr->createElement( bstrName );
DomDocPtr->appendChild( DomRoot );
GenTree( DomRoot, tagRootPart );
// 保存XML文件
DomDocPtr->save( XML_FILE_NAME );
}
void GenTree( MSXML2::IXMLDOMElementPtr XmlRoot, tag_t AssRoot )
{
int iChildCount = -1;
tag_t* Children = NULL;
iChildCount = UF_ASSEM_ask_part_occ_children( AssRoot, &Children );
if ( iChildCount > 0 )
{
for ( int i = 0; i < iChildCount; i++ )
{
// 取得子组件的文件名
char szBuffer[ MAX_FSPEC_SIZE + 1 ];
UF_PART_ask_part_name(
UF_ASSEM_ask_prototype_of_occ( *( Children + i ) ), szBuffer );
ProcFilename( szBuffer );
MSXML2::IXMLDOMElementPtr DomElement = NULL;
_bstr_t bstrName;
bstrName = szBuffer;
MSXML2::IXMLDOMNodePtr DomNode = NULL;
DomNode = XmlRoot;
DomElement=
DomNode->GetownerDocument()->createElement(bstrName);
XmlRoot->appendChild( DomElement );
// 用递归的方法对装配树进行遍历
GenTree( DomElement, *( Children + i ) );
}
}
return;
}
6 结论
在NX的二次开发当中,利用二次开发提供的功能可以对整个装配树进行遍历,从而取得所有的子组件以及这些子组件的所有信息(包括装配信息、附加信息等),从而方便的对这些数据进行统计、处理。
[参考文献]
[1] Open C Reference Guide
[2] NX Open C++ Reference Guide
[3] MSDN Library .Net 2003
本帖最后由 wgmqq2008 于 2010-12-12 15:38 编辑 |