UG/ OPEN++类库
概述
UG/Open++有五种不同的类:应用程序类,对象类,模板类,辅助类,和数学类。
1, 应用程序类:
控制UG应用程序的运行。包括:UgSession,UgInfoWindow,和 UgException。
2, 对象类:
定义可以作用于UG零件文件中包含对象的属性和操作。例如,UgArc,UgFace,和UgExpression等。表示UG零件的UgPart类,也属此类。
3, 模板类:
提供平台无关的标准模板库(STL)类,主要用于数组和字符串。还有一个遍历UG/Open++对象的模板类。
4, 辅助类:
定义用于其它类定义中的临时对象。例如:ThruPoint和Evaluator类等。
5, 数学类:
包括通用数学对象。与UG对象类结合使用,非常有帮助。数学类包括点,向量,矩阵,坐标系等类。
通常情况下,每个类都定义在一个独立的头文件中,文件名是该类的名字。例如UgArc类定义在ug_arc.hxx文件中。有时一个头文件也包含诸如辅助类等的一些其它类定义。
在UG/Open++中,你可以任意调用一个类的公用方法,但不能调用其私有方法。保护方法只能在导出类中调用。
●应用程序类
对话期类(Session)
UgSession 类的一个主要作用是进行UG/Open的初始化。这个初始化是在其它任何UG/Open++方法被调用之前必须进行的。对话期的初始化和终止由两个静态方法完成,它们是UgSession::initialize ( ) 和 UgSession::terminate ( ):
UgSession::initalize();
// 你的 UG/Open++ 代码
UgSession::terminate();
另外一种方法是创建一个UgSession对象:
UgSession mySession ( true );
// 你的UG/Open++ 代码
关于UgSession,有两个地方需要注意:
1. UgSession析构方法将会自动结束UG/Open。这在超出UgSession对象的作用范围之外时,将会自动发生。
2, 当你用以下语法进行创建UgSession对象时,UG/Open的初始化将被阻止,并且析构方法也不能终止这个对话期:
UgSession mySession;
从功能上讲,上面提到的两种对话期初始化方法与传统的UF_initialize()方法是完全一样的,在程序的开始,可以使用任何一种方法,但不能同时使用两种不同方法。这样在下面的程序中,UG/Open++和传统的UG/Open方法就可以被调用。
UgSession也可以用于控制当前UG对话期的状态和行为。例如,一些UgSession的方法可以改变当前工作零件,修改层状态,以及关闭所有的零件等。
●对象类:
对象类主要定义可以作用于UG零件文件中包含对象的属性和操作。例如,UgArc,UgFace,和UgExpression等。表示UG零件的UgPart类,也属此类。大多数的UG/Open++应用程序都涉及对UG对象的操作。
对象类分为两种:基类和叶类。基类定义作用于一组相关对象的通用操作,而且它们没有CREATE()方法。叶类定义的是作用于某一特定类型物体的操作,而且大多数都定义了CREATE()方法。基类表示一组类似的UG对象,而叶类表示一种具体的UG对象。
类的体系关系提供了充分的UG功能性的层次划分,用基类定义这类对象的公用的操作。另外,在某些时候它利用多重继承来定义没有关系的对象的通用接口。
所有UG对象最顶层的基类叫做UgObject。它定义了一些所有UG对象都可以使用的通用方法。 例如UgObject::askOwningPart ( )返回一个UG对象所在的零件。
其它基类都来自UgObject类的派生,包括UgTypedObject和UgDisplayableObject(注意绝大多数在UG/Open++中的基类都是以关键字`Object'结束命名的)。UgTypedObject提供为UG物体命名或删除物体的方法,而 UgDisplayableObject提供诸如更改颜色、图层等方法。
创建对象
UG/Open++ 层次结构树的叶子,是真正代表具体UG对象的C++类,例如UgArc表示弧线,UgExpression代表表达式。这些类叫做可实例类,因为可以创建这些类的C++对象,而且每个创建的对象都对应一个UG零件文件包含的UG对象。要创建一个UG对象,只需调用创建对象的静态方法CREATE(),如下所示:
UgPart *pWorkPart = UgSession::getWorkPart ( );
UgExpression *pExpr;
pExpr = UgExpression::create ( "diameter", 4.25 , pWorkPart );
double diaValue = pExpr->evaluate ( );
UG对象都是用指针的方式被引用,而不是用对象名称,如上例中的pExpr。事实上,C++的构造函数是一个保护方法,这样可以避免在不适当的地方错误调用该构造函数。用指针引用减少了内存的使用,并且保证写出的C++代码与UG模型在任何时候都保持同步。
UgAssemblyNode类是一个没有CREATE()方法的叶类。此类的对象创建是用UgPart::addPart ( ):
UgPart *pWorkPart = UgSession::getWorkPart ( );
UgAssemblyNode *pNode;
pNode = pWorkPart->addPart ( "component.prt", "", "",CoordSys ( ), -1 );
一些类覆盖了静态的CREATE()方法,而用其它方法创建UG物体。
下面介绍三种创建表达式的方法:
UgPart *pWorkPart = UgSession::getWorkPart ( );
UgExpression *pExpr1, *pExpr2, *pExpr3;
UgString strName ( "diameter1" );
pExpr1 = UgExpression::create ( "radius", 4.25, pWorkPart );
pExpr2 = UgExpression::create ( "diameter=2*radius", pExpr1 );
pExpr3 = UgExpression::create ( strName, "2*radius" );
所有的create函数的最后一个参数都是一个选项参数,来指定零件上下文,也就是说新创建对象的宿主零件。如果没有指定该参数,则属于当前工作零件。这个参数既可以是一个指向零件对象的指针,也可以是一个指向属于该零件对象的其它对象的指针。例如:
UgPart *pOtherPart;
// 初始化 pOtherPart 来指向一个可用的UG零件对象
UgExpression *pExprNew;
pExprNew = UgExpression::create("length=3.0", pOtherPart);
权限控制
当一个指向UG物体的指针被定义后,就可以用它来调用该类及其父类定义的所以方法。例如,如果pArc是一个指向UgArc的指针,那么就可以调用pArc的方法对该UG弧线对象进行查询或修改,代码如下所示:
pArc->setRadius ( 2.5 );
double len = pArc->computeArcLength ( );
int layer = pArc->getLayer ( );
上例中调用的三个方法都可以被UgArc对象调用。但只有setRadius()方法在UgArc类中被定义,其它两个方法都是在其父类中定义的。
标志与指针转换
UG/Open++ 允许开发代码中包含传统的UG/Open代码,并且进行相关的数据传递。这就需要进行在UG/Open++的指针和UG/Open的标志之间进行转换。 UgObject::find ( ) 和 UgObject::getTag()两个方法可以完成此类转换。UgObject::find ( )返回一个指向UgObject对象的指针,因此还需要进行类型的强制转换(请参考动态类型转换一节)。例如:
int color;
tag_t tag1, tag2;
// Call the traditional UG/Open function to select a line.
// Note: this returns the tag of the selected line as `tag1'
UF_UI_select_single ( ..., &tag1, ... );
// Use the `find' method to get the pointer of the Unigraphics
// object corresponding to `tag1'
UgObject *pObj = UgObject::find ( tag1 );
if ( pObj )
{
UgLine *pLine = dynamic_cast <UgLine *> pObj;
if ( pLine )
{
// Invoke a UG/Open++ method using that pointer
pLine->setColor ( Red );
// Now convert the pointer back to a tag (`tag2').
// Note that `tag1' and `tag2' should be identical.
tag2 = pLine->getTag ( );
// Call a traditional UG/Open function to get the color
// using `tag2' – it should be Red.
UF_OBJ_ask_color ( tag2 , &color );
}
}
从以上的例子可以看出,如果一个UG对象没有创建方法的话,UgObject::find ( )方法有可能返回0。所以,一般来讲,对UgObject::find ( )返回的指针进行检查并进行强制类型转换很有必要。这样可以确保无误。
零件
UgPart 类定义了UG零件的方法,包括创建新零件,打开已存在零件,零件存盘,关闭打开的零件等。要注意的是关闭一个零件的方法属于UgPart类,而关闭所有零件的方法属于UgSession类。UgPart类还包含读取和修改零件属性以及其它存储在零件文件中数据的方法。例如,
UgPart *pPart = UgPart:open( "valve.prt" );
// Find out what the part units are
bool isItMetric = pPart->isMillimeters ( );
UgPart::iterateFirst ( ) 和 UgPart::iterateNext ( )两个方法提供了遍历存储在该零件中所有UG对象的机制。首先UgPart::iterateFirst ( )被调用,并返回一个零件中的第一个对象。然后,通过不断调用以上一个已访问对象为参数的UgPart::iterateNext ( )方法,遍历过程继续直到所有的对象都被访问,此时UgPart::iterateNext ( )返回0。例如:
UgPart *pWorkPart = UgSession::getWorkPart();
UgTypedObject *pCurObj;
for ( pCurObj = pWorkPart->iterateFirst ( );
pCurObj;
pCurObj = pWorkPart->iterateNext ( pCurObj ) )
{
UgString name = pCurObj->getName ( );
}
需要注意的是,由于这个遍历方法可以访问各种不同类型的对象,所以返回的是一个指向基类UgTypedObject的指针。那么,只有定义在类UgTypedObject的方法才能被调用,例如读取对象名称和属性。如果想调用特定类定义的方法,就必须进行类型的强制转换。
另一种遍历方法是利用模板类UgIterator所定义的方法,这将在后面的模板类一节中讲到。
原型与实例
UG 中原型和实例的概念主要用于在装配访问和操纵UG物体。原型指在一个零部件中的具体几何物体,而实例则定义该原型物体在装配中的位置和取向。当你用 UG/Open++遍历一个UG物体时,有可能会同时访问到一个物体的原型和实例。如果访问到的是原型物体,则可以对其进行读取和修改的操作。但是,如果访问到的是一个实例物体,那么只能进行读取操作,直接的修改是不允许的。无论你访问的是一个原型物体或者实例物体,通常都采用下面的方式进行修改:
UgLine *pLine;
// Initialize the pLine pointer
Point3 newPt;
. . .
// Set the end point of the line to (0.0, 0.0, 0.0)
( pLine->askPrototype ( ) )->setEndPoint ( newPt );
请注意:如果pLine是一个实例物体,那么UgLine::askPrototype ( )会返回与其对应的原型物体。如果它已经是一个原型物体,那就返回其本身。
下面的例子说明如何确定一个物体是原型物体,还是实例物体:
UgLine pLine;
// Initialize the pLine pointer
. . .
if ( pLine->isOccurrence ( ) )
{
// it’s an occurrence
}
else
{
// it’s a prototype
}
曲线和边界
UG 将一般线框曲线和实体的边界曲线分别对待。但是,在开发上,UG的类层次结构也允许对它们用相同的代码进行处理。由于线框曲线和实体边界都以 gEvaluatableObject为基类,所以可以用相同的方式进行处理。如下例,在计算弧长和求弧线与其它物体的交点时,无须为类型检验而编码。
UgEvaluatableObject *pObj1, *pObj2;
// Assume the user selected pObj1 and pObj2 so you don't know
// their types (i.e. the user might have selected an edge
// and a wireframe curve)
// Get the arc length of each object, regardless of type
double len1 = pObj1->computeArcLength ( );
double len2 = pObj2->computeArcLength ( );
// Compute the intersection points for these two objects
UgArray<CurveCurveIntersectionPoint> iPts;
iPts = pObj1->computeIntersectionPoints ( pObj2 );
此外,还可以通过UgEvaluatableObject::askEvaluator ( )方法返回的Evaluator对象访问实体边界和线框曲线上任意点的坐标和法向量。
上面提到的方法在作用于EvaluatableObject类型的对象,无论是直线,圆弧,直线边界,还是曲线边界等,都无须做类型检查。在另外一些情况下,可能需要访问更加具体的物体信息,例如想得到圆弧物体的半径,而事先并不清楚该物体是线框圆弧曲线,还是实体的圆弧边界,这类情况也可以用如下的方法处理,而无须进行类型检查:
UgEvaluatableObject *pCircularObj;
// Initialize pCircularObj to some circular object,
// but not know whether it is a wireframe arc or
// a circular solid edge.
// Get the generic curve object for it. The dynamic cast
// should work since we know we have an arc or circular edge.
Arc *pArc = dynamic_cast < Arc * > pCircularObj->askCurve ( );
// Now we can do specific inquiries on it
double radius = pArc->getRadius ( );
●模板类
UG/Open++ 的模板类主要是用于字符串(UgString)和动态数组(UgArray)的处理。字符串和数组作为UG/Open++方法的输入和输出参数非常常用。它们和C++模板库(STL)中的string和vector类非常相似。一个比较明显的区别是STL类提供遍历方法,而UG/Open++类不提供。因为UG对STL并不完全支持,所以对应的STL类不能在UG/Open++中使用。这有可能在将来的版本中实现。请看下例:
UgPart *pMyPart;
// Initialize the pMyPart pointer
// Get the description string for this part
UgString description=pMyPart->getDescription ( );
// Make sure it isn't a null string
if (!description.empty ( ))
{
// do something with it
}
为了与C语言函数兼容,UG/Open++也容许使用UgObject对象返回符合C语言语法的字符串指针。如果上例中的description是UgString对象,下面的代码就是正确的:
printf( "Description = %s/n", description.c_str() );
值得一提的是这类指针只能被用作指针常量,因此不能通过这样的指针对字符串进行修改。
遍历模板类
一般情况下,都使用UgIteration类来进行一组同类对象的遍历。例如:
// Construct an iterator for Unigraphics face objects
UgIterator < UgFace *> curFace;
// Loop through all faces
while ( !curFace->isFinished ( ) )
{
// Get the name of the current face
UgString faceName = (*curFace)->getName ( );
curFace->findNext ( );
}
遍历所有这些同类对象一般需要三步:
1, 创建一个遍历模板对象。UgIteration是一个模板类,也就意味着可以使用同样的方式遍历不同类型的UG类。当创建UgIteration对象时,需要指定具体的UG类型,例如上例中的(UgFace *)。该类必须是可实例化的,因此如果要对一个UgConicObject的基类创建UgIteration对象,就会在编译时出错。 UgIteration的构造方法有一个可选参数(上例中没有使用),通过它可以遍历不是当前工作零件的其它零件中包含的对象。
2, 循环访问所有想要访问的对象,每次只能访问一个对象。While循环在UgIteration对象的方法UgIterator < UgFace *>::isFinished ( )返回真时结束。
3, 在while循环中,将*操作符作用于UgIterator对象,以获得一个当前访问对象的指针。在上例中,(*curFace)就返回一个指向UgFace对象的指针。
也可以使用UgIterator 类以如下的方式来访问所有在当前对话期内载入的UG零件。
// Construct an iterator for Unigraphics part objects
UgIterator < UgPart *> curPart;
// Loop through all loaded parts
while (!curPart->isFinished ( ))
{
// Close this part if it is not metric
if ( !(*curPart)->isMillimeters ( ) )
{
(*curPart)->close ( true );
}
curPart->findNext ( );
}
●辅助类
UG/Open++包含许多辅助类。它们主要用于为定义在其它类中的方法来回传递数据。例如,ThruPoint一般用于指定UgSpline曲线上任意点的位置,斜率和曲率。如下所示:
UgSpline *pSpline;
// Initialize pSpline pointer
UgArray < ThruPoint > thruPts; // Array of ThruPoint objects
UgArray < double > params; // Array of doubles
bool periodic;
int order;
// Get defining data for a spline
pSpline->getThruPoints ( &periodic, &order, &thruPts, ¶m );
注意:与其它UG类不同,辅助类的名称不以字母UG开头。
●数学类
vmathpp库包含常用的数学操作类。主要是对点,向量和矩阵的处理。这些类的对象在调用UG对象的方法时非常有用。数学类的许多标准操作都已被重载,以使代码更加简洁和易读。例如,
Point3 pt1 ( 0, 2, 4 );
Vector3 offset ( 1, 2, 3 );
Point3 pt2 = pt1 + offset;
UgLine *pLine = UgLine::create ( pt1, pt2 );
关于vmathpp库的另一个要点是它包含的类与UG完全独立。在与UG无关的其它应用程序中也可以被调用。