3D PLM PPR Hub Open Gateway

Knowledge Modeler

Integrating the Knowledge Language

How to integrate its applicative objects and user functions
Technical Article

Abstract

This article explains how to integrate your own objects in CATIA, so that they can be recognized by generic tools and so that they can be interpreted by the Knowledge language.


Introduction

Let's introduce vocabulary: the Knowledge browsers manipulate the notion of packages, types and attributes.

The following image represents the Knowledge Expert browser.

All the available object types are classified in packages. For example, you have the Electrical package, the GSD package or the PartDesign package selected above. A package contains a set of types which can be pre-defined CATIA types or User types. A type is constituted of attributes. An attribute can be a simple value or an object.

Besides integrating User types, you can create User functions manipulating any types ( pre-defined types or user types). These functions are classified in method packages. It is also visible in Knowledge browsers.

Each type, attribute and function displayed in the Knowledge Expert browser above can be used in a Knowledge Expert rule.

These types and functions are C++ objects created at runtime and gathered in a single dictionary.

To be able to manipulate your own objects this way, you have to implement several interfaces and declare ressources.

[Top]

Where to Find a Code Example

The CAALifIntegrateKnowledge.m module of the CAALiteralFeatures.edu framework is a shared library containing an example of definiton of user types and user functions.

Windows InstallRootDirectory\CAALiteralFeatures.edu\CAALifIntegrateKnowledge.m\
Unix InstallRootDirectory/CAALiteralFeatures.edu/CAALifIntegrateKnowledge.m/

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Adding New User Types

What To Do

To create a new type you have to implement the CATIAddTypeLibrary interface of KnowledgeInterfaces. Let's call this implementation MyLibrary.

In the Add method of this interface you will specify your new type with its attributes and to which package it belongs. Also, you will specify its father type: a type has to inherit from another one. The basic type is the type "Feature". Your new type will inherit from the attributes of its father type.

To create packages and types use the CATITypeDictionary interface which is dedicated to accessing the dictionary of types shown to the user. To retrieve a smart pointer on this unique type dictionary, you can use the static GetTypeDictionary method of the CATGlobalFunction class.

CATITypeDictionary_var dico;
dico = CATGlobalFunctions::GetTypeDictionary();

Let's add a package "DoItYourself",

CATListOfCATUnicodeString iListOfPrerequisites;
rc = dico->AddPackage( "DoItYourself", iListOfPrerequisites );

iListOfPreriquisites contains the list of the required packages necessary to have the types from which we derive.

In this package, let's create a user type "Screw" with 2 length attributes Dim1 and Dim2:

First, you have to get the type of your attributes in the parameter's type dictionary.

CATIParmDictionary_var spParmDictionary = CATCkeGlobalFunctions::GetParmDictionary();
CATICkeType_var spType = spParmDictionary->GetLengthType();

Then, create the attributes of your type specifying their type, name, NLS name, if it is writable and if it contents a component ...

CATAttributeInfos attribute1( spType, "Dim1", "Dim1", 1, 1 );
CATAttributeInfos attribute2( spType, "Dim2", "Dim2", 1, 1 );

Put the attributes in a list ...

CATListValCATAttributeInfos listAttributes;
listAttributes.Append( attribute1 );
listAttributes.Append( attribute2 );

At last, create your type "Screw" with the list of attributes in argument, and add the type in the package "DoItYourself".

CATIType_var typeScrew = NULL_var;

dico->CreateType( "Screw", "Screw", NULL_var, typeScrew, &listAttributesScrew);
dico->AddTypeForPackage( typeScrew, "DoItYourself" );

 

To allow the creation of an instance of the implementation MyLibrary, you have to implement the CATICreateInstance interface of System through a CodeExtension of the component to create. The necessary method to implement is CreateInstance in which you make a simple new of the wanted implementation MyLibrary.

HRESULT __stdcall CAALifAddLibraryExt::CreateInstance (void ** ppv)
{
*ppv = new MyLibrary;
return S_OK;
}

You need to implement CATIAddTypeLibrary and CATICreateInstance only once in your library. Ideally, this code should be in a small DLL so that retrieving the definition of types doesn't load all your code.

Then you have to edit your dictionary to specify that:

    - the implementation MyLibrary implements CATIAddTypeLibray in a given library,

    - the implementation MyLibrary implements CATICreateInstance in a given library

    (always specify in a dictionary, the implementation and not the extension).

 

Finally, you have to create a resources file named CATPackageXXX.CATRsc, where XXX is the name of your package. This file contains one line declaring the link between your package and its implementation class (PackageImplementation = "MyLibrary") . It can also contain description for each type for documentation.

[Top]

How It Works - Loading Process

Let's describe the algorithm executed to retrieve all the types.

In Tools/Options, the user can specify the packages he needs in order to work. The list of the needed packages is obtained by scanning the .CATRsc files beginning by "CATPackage". The name mapping is the following: CATPackageXXX.CATRsc with XXX = the package name. This resource file indicates the necessary implementation class. Then we search in the dictionary, the library in which this implementation class implements the CATICreateInstance interface and we execute its CreateInstance method. It returns an instance of the implementation class implementing the CATIAddTypeLibrary interface. Finally we can call the Add method of the CATIAddTypeLibrary.

If necessary, you can also ask in your code to load a library with the CATIParmDictionary::LoadLibrary service taking the implementation class name in argument.

[Top]

Adding New User Functions

If you need to add method or function specific to your application types, do it the same way in the Add method of CATIAddTypeLibrary.

Be carefull, you have to create a package specific to these user functions. The name of this package must look like "CATPackageMethodXXX".

You have to create  a CATPackageMethodXXX.CATNls file specifying the package name of your functions which will be seen in the knowledge editors (PackageName = "My Functions").

First, create the signature of your function with the CATICkeFunctionFactory::CreateFunction service. Its arguments are its name, the type of the returned value, the name of the C++ function, a NULL argument, and an enumerated value to express the format of your function(method x.f(y), function f(x,y) or attribute x.y).

Here, we create a volume function called "EvaluateScrewVolume" to calculate the volume of an object of type Screw. We want the result as a real value. The evaluation is in a C++ function called VolumeFunction ( see in CATAddLibrary.cpp). It will be a function rather than a method.

CATICkeType_var ReturnedType = NULL_var;
ReturnedType = spParmDictionary->GetRealType();

CATICkeFunctionFactory_var funcFactory = CATCkeGlobalFunctions::GetFunctionFactory();

CATICkeSignature_var Sign = funcFactory->CreateFunction ("EvaluateScrewVolume",ReturnedType,VolumeFunction,NULL,CATICkeSignature::Function);

Then, add to the signature an argument of type Screw which will be taken in input of the function to produce the volume result.

Sign->AddArgument (funcFactory->CreateArg ("iA",typeScrew));

Finally, create a method package and add the signature of your user function in it.

rc = dico->AddPackage( "CATPackageMethodDoItYourself", iListOfPrerequisites );
...
dico->AddMethodForPackage( Sign, "CATPackageMethodDoItYourself" );

See Writing a User Function [1] for more information on how to write a user functions.

   [Top]

Manipulating User Objects

Now that you have defined the type/attribute view, it is time to indicate how to manipulate the objects themselves. For that you have to implement the CATIInstance interface dedicated to manipulate objects in Knowlegdeware.

With this implementation, your will create a specific view of existing objects responding to user types. For example, you will create a simplified view of a geometrical feature compared to its internal modelisation. Only relevant attributes for the user will be visible in the Knowledge browsers.

Your implementation class will be an extension of the object you want to expose to the user with a simplified view. This object can be a feature or a simple C++ object. This implementation should derive from CATKweInstanceAdapter.

In the methods Type and ListSupportedTypes, you will indicate the main type of your object and its others types ( we assume multi - type objects). The types you returned are taken in the packages you have previously defined.

 

Implementation of the Type method:

CATIType* CAALifInstanceScrewExt::Type() const
{

...
CATIType_var TypeInDico = NULL_var;

rc = dico->FindTypeSafe("Screw","DoItYourself",TypeInDico);
...

return TypeInDico;
}

Always use the FindTypeSafe method, which load the package if the type isn't found in first step.

In the methods GetValue and SetValue, you manage the attributes of your object: what are they and how are they valuated.

These two methods manipulate CATIValue. This interface is a union of different types of object. It can be values (parameters) or features (in features, we include List of features).

 

Implementation of the SetValue method: CAALifInstanceScrewExt::SetValue( const CATUnicodeString& iKey, const CATIValue_var& iValue )

The argument iKey is the name of the attribute we want to valuate, and the argument iValue contains the value of the argument (parameter or feature)

Let's get a handler on the attribute manager of the object, and also the key of the attribute you want to modify.

CATISpecAttrAccess_var piSpecAttrAccess = GetImpl();

...

CATISpecAttrKey *attrkey = piSpecAttrAccess->GetAttrKey(iKey);

According to the wanted attribute, you may have different manner to valuate it.

The attribute is a parameter:

if (iKey == "ScrewLength" || iKey == "ScrewHeadDiameter" || iKey == "ScrewStemDiameter")
{
   CATISpecObject_var SpecParm =  piSpecAttrAccess->GetSpecObject(attrkey);
   ...
   CATICkeParm_var Parm = SpecParm;
   Parm->Valuate(iValue->AsReal());
}

Always valuate an attribute parameter with the value of the parameter located in the CATIValue in argument.

Or the attribute is a feature:

else if (iKey == "CenterPoint")
{
   CATISpecObject_var newSpecObj = iValue->AsObject();
   piSpecAttrAccess->SetSpecObject(attrkey, newSpecObj);
   ...
}

Implementation of the GetValue method: CATIValue* CAALifInstanceScrewExt::GetValue( const CATUnicodeString& iKey )

The argument iKey is the name of the attribute from which you want the value.

If the wanted attribute is a parameter:

CATISpecObject_var obj = NULL_var;
if (iKey == "ScrewLength" || iKey == "ScrewHeadDiameter" || iKey == "ScrewStemDiameter")
{
  CATIValue_var value = NULL_var;
  obj = piSpecAttrAccess->GetSpecObject(attrkey);
  attrkey->Release();

  if (obj != NULL_var)
    obj->Release();
...

We return a pointer on a CATIValue

CATIValue* returnedValue = NULL;
CATIValue_var value = NULL_var;
value = obj;

if (value != NULL_var)
{
  returnedValue = value;
  returnedValue->AddRef();
}
return returnedValue;

If the wanted attribute is a feature:

First we get the feature ...

CATISpecObject_var obj = NULL_var;

if (iKey == "CenterPoint")
{
  obj = piSpecAttrAccess->GetSpecObject(attrkey);
  attrkey->Release();
  if (obj != NULL_var)
    obj->Release();
  ...

Then we have to transform this feature in a CATIValue*. For that we need a volatile factory.

CATICkeParmFactory_var VolFactory = CATCkeGlobalFunctions::GetVolatileFactory();

From the volatile factory we create a parameter from the feature. And finally we make a QueryInterface from the parameter to get a CATIValue*.

CATICkeParm_var parm = VolFactory->CreateObjectReference(obj);
CATIValue* returnedValue = NULL;
if(parm != NULL_var)
  parm->QueryInterface(CATIValue::ClassId(), (void **)&returnedValue);
...
return returnedValue;
...

The returned CATIValue pointer must be released in the context where it will be used when it is becoming useless.

[Top]

Visibility in Knowledge Browsers

Your objects will be visible in Knowledge Expert if they are accessible through the CATIParmPublisher interface from the root of the document (Part, Product, etc.)

In Knowledge Expert, you will see your package, your types and their attributes. If there are some user methods, they will be displayed at the same level as the attributes. If there are some user functions, they will be displayed when selecting the "Functions" package.

In Knowledge Advisor, you can only see your method packages and the corresponding methods/functions. User types will be visible only in the signature of methods/functions. If your object implement the CATICkeFeature interface, you will be able to select one of these object to write a call to a method/function in the editor. Specifically to the Reaction/Action editor, the access to feature's attributes will be possible. To finish, if your object implements the CATIParmPublisher interface, the attributes of type parameter of your object will be visible in the Knowledge Advisor browser.

[Top]


In Short

The Knowledgeware allows to integrate your own object, functions or method in oder to create a simplified user view of your data.

For that, you have to create a few resources files and to implement the interfaces CATIAddTypeLibrary, CATICreateInstance and CATIInstance.

Afterwards, your object user view will be accessible and understood in the Knowledge language.


References

[1] Writing a User Function
[Top]

History

Version: 1 [Nov 2003] Document created
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.