3D PLM PPR Hub Open Gateway |
Feature Modeler |
Aggregating Features to FeaturesWorking with aggregated features |
Use Case |
AbstractThis article discusses the CAAOsmAggregatedAttr use case. This use case aims to explain how to create and assign aggregated attributes to features and the concepts related to them. |
This use case is intended to help you understand the basics of working with aggregated attributes. Its main intent is to explain the nature of aggregated attributes, how to create them and how to assign them to features. Through this use case, you will also learn some important aspects recommended when programming with features. Specifically, you will learn how to:
Before getting to the use case itself, it is important to get an understanding of what a feature object is and how it is created [1].
[Top]
CAAOsmAggregatedAttr is a use case of the CAAObjectSpecsModeler.edu framework that illustrates ObjectSpecsModeler framework capabilities.
[Top]
The goal of the CAAOsmAggregatedAttr use case is to illustrate adding features to features as tk_component attributes. These features are said to be "aggregated".
Several chapters for a given novel, The Three Musketeers, are described here. This use case uses the catalog defined in the CAAOsmCatalogSU use case [2] which contains StartUps from the "Book" example. We want to assign titles to the chapters and describe their length by giving the first and last page numbers they cover. The "CAAOsmChapter" StartUp is retrieved from the catalog. Its attributes are "ChapterTitle", "FirstPage" and "LastPage". Three "CAAOsmChapter" instances of the StartUp are created. Their attributes are valuated and each feature is assigned to the novel as an item in a list (list of chapters). The "CAAOsmChapter" feature has been defined as an aggregated feature in order to limit its existence to only one novel: a chapter is unique, it cannot exist in more than one novel.
Working with lists is also illustrated here by scanning through the chapter titles of "CAAOsmNovel1".
[Top]
To launch CAAOsmAggregatedAttr, you will need to set up the build time environment, then compile CAAOsmAggregatedAttr along with its prerequisites, set up the run time environment, and then execute the sample.
mkrun -c "CAAOsmAggregatedAttr CAAOsmCatalogSU.CATfct DocumentStorageName.CATPart"
This is fully described in the referenced article [3]. When launching the use case, you must pass the following arguments:
[Top]
CAAOsmAggregatedAttr code is located in the CAAOsmAggregatedAttr.m use case module of the CAAObjectSpecsModeler.edu framework:
Windows | InstallRootDirectory\CAAObjectSpecsModeler.edu\CACAAOsmAggregatedAttr.m |
Unix | InstallRootDirectory/CAAObjectSpecsModeler.edu/CAAOsmAggregatedAttr.m |
where InstallRootDirectory
is the root directory of your CAA V5
installation. It is made of a unique source file named CAAOsmAggregatedAttr.cpp.
[Top]
There are eight logical steps in the CAAOsmAggregatedAttr:
We will now comment each of these sections by looking at the code.
[Top]
See the referenced article [4] for a detailed description of the steps to go through when creating a new document.
In this use case, we create a new "Part" document: CATDocument
*pDoc
, and retrieve its root container: CATIContainer *piRootContainer
.
[Top]
Loading the catalog means opening the catalog document and getting a CATICatalog handle that will be needed in order to retrieve StartUps from the catalog.
CATUnicodeString stgName = argv[1]; CATICatalog *piCatalog; CATUnicodeString clientId("CAAOsmClientId"); rc = ::AccessCatalog (&stgName, &clientId, piRootContainer, &piCatalog); if (SUCCEEDED(rc)) cout << "Catalog accessed OK" << endl << flush; else { cout << "ERROR on AccessCatalog" << endl << flush; piRootContainer -> Release(); return 5; } |
To open a catalog, use the AccessCatalog
global function that
takes the following arguments:
catalogName
- the name of the catalog without the storage
path and with the .CATfct extension. The catalog must be found under the
"WS" + "OS" + resources + graphic directory.clientId
- the client id defined on the catalog at the time
of its creation.piRootContainer
- a CATIContainer pointer to the
container in which StartUps from the catalog will be instantiated.piCatalog
- a CATICatalog pointer to the StartUps
catalog that has been opened.[Top]
CATBaseUnknown *pChapterSU = NULL; CATUnicodeString chapterSUType("CAAOsmChapter"); rc = piCatalogOnContainer -> RetrieveSU(&pChapterSU, &chapterSUType, "CATISpecObject"); if (NULL != pChapterSU) cout << "CAAOsmChapter StartUp retrieved OK" << endl << flush; else { (Process ERROR: Release pointers and return.) } // Get a CATISpecObject handle on the CAAOsmChapter StartUp CATISpecObject *piChapterSU = (CATISpecObject*) pChapterSU; |
A StartUp is retrieved from the catalog using the CATICatalog::RetrieveSU
method. This method returns a CATBaseUnknown pointer in pChapterSU
which is directly cast into a CATISpecObject pointer (piChapterSU
).
The CATBaseUnknown pChapterSU
pointer must be released
when no longer needed.
CATISpecAttrAccess *piSpecAttrAccessOnChapt = NULL; rc = piChapterSU -> QueryInterface(IID_CATISpecAttrAccess, (void**) &piSpecAttrAccessOnChapt); if (FAILED(rc)) { (Process ERROR: Release pointers and return.) } CATISpecAttrKey *piKeyChapterTitle = piSpecAttrAccessOnChapt -> GetAttrKey("ChapterTitle"); if (NULL == piKeyChapterTitle) { (Process ERROR: Release pointers and return.) } CATISpecAttrKey *piKeyFirstPage = piSpecAttrAccessOnChapt -> GetAttrKey("FirstPage"); if (NULL == piKeyFirstPage) { (Process ERROR: Release pointers and return.) } CATISpecAttrKey *piKeyLastPage = piSpecAttrAccessOnChapt -> GetAttrKey("LastPage"); if (NULL == piKeyLastPage) { (Process ERROR: Release pointers and return.) } piSpecAttrAccessOnChapt -> Release(); |
Once we have a pointer to the StartUp, the first thing to do is to get
the attribute keys that will be needed later on in order to valuate the
attributes. Using the CATISpecObject handle, we get a CATISpecAttrAccess
handle with which we execute the GetAttrKey
method in order to
get the attribute keys.
CATUnicodeString chapter1("CAAOsmChapter1"); CATISpecObject *piChaptInst1 = piChapterSU -> Instanciate(chapter1, piRootContainer); if (NULL != piChaptInst1) cout << "CAAOsmChapter SU instance 1 created OK" << endl << flush; else { (Process ERROR: Release pointers and return.) } |
Now we are finally ready to create a first feature object by
instantiating the StartUp "CAAOsmChapter". This is done using the Instanciate
method of CATISpecObject.
CATISpecAttrAccess *piSpecAttrAccessOnChapt1 = NULL; rc = piChaptInst1 -> QueryInterface(IID_CATISpecAttrAccess, (void**) &piSpecAttrAccessOnChapt1); if (FAILED(rc)) { (Process ERROR: Release pointers and return.) } piSpecAttrAccessOnChapt1 -> SetString(piKeyChapterTitle, "The Three Presents of M.D Artagnan, the Father"); piSpecAttrAccessOnChapt1 -> SetInteger(piKeyFirstPage, 11); piSpecAttrAccessOnChapt1 -> SetInteger(piKeyLastPage, 27); piSpecAttrAccessOnChapt1 -> Release(); |
Once the feature has been created, its attributes can be valuated using
the Set...
methods of CATISpecAttrAccess. So first of
all, let's get a CATISpecAttrAccess handle on the new feature
"CAAOsmChapter1" and then valuate the attributes.
The same procedure for creating and valuating attributes is performed on two more "CAAOsmChapter" features: "CAAOsmChapter2" and "CAAOsmChapter3".
[Top]
The three "CAAOsmChapter" features previously created will be added as a list to the feature "CAAOsmNovel1" which must first be created based on the StartUp "CAAOsmNovel".
CATBaseUnknown *pNovelSU = NULL; CATUnicodeString novelSUType("CAAOsmNovel"); rc = piCatalogOnContainer -> RetrieveSU(&pNovelSU, &novelSUType, "CATISpecObject"); if (NULL != pNovelSU) cout << "CAAOsmNovel StartUp retrieved OK" << endl << flush; else { (Process ERROR: Release pointers and return.) } // Get a CATISpecObject handle on the CAAOsmNovel StartUp CATISpecObject *piNovelSU = (CATISpecObject*) pNovelSU; // Retrieve the CAAOsmNovel's attribute key "NovelChapter" CATISpecAttrAccess *piSpecAttrAccessOnNovel = NULL; rc = piNovelSU -> QueryInterface(IID_CATISpecAttrAccess, (void**) &piSpecAttrAccessOnNovel); if (FAILED(rc)) { (Process ERROR: Release pointers and return.) } CATISpecAttrKey *piKeyNovelChapter = piSpecAttrAccessOnNovel -> GetAttrKey("NovelChapter"); if (NULL == piKeyNovelChapter) { (Process ERROR: Release pointers and return.) } piSpecAttrAccessOnNovel -> Release(); // Get an instance of the CAAOsmNovel StartUp CATUnicodeString novel1("CAAOsmNovel1"); CATISpecObject *piNovelInst1 = piNovelSU -> Instanciate(novel1, piRootContainer); pNovelSU -> Release(); if (NULL != piNovelInst1) cout << "CAAOsmNovel SU instance 1 created OK" << endl << flush; else { (Process ERROR: Release pointers and return.) } |
We proceed, therefore, as we have before, by retrieving the StartUp and its attribute keys and then instantiating it.
[Top]
Now, the "CAAOsmChapter" features can be assigned to
"CAAOsmNovel1" as a list of objects of the attribute
"NovelChapter" defined in the StartUp as a tk_list
of tk_components
.
This means that the attribute "NovelChapter" will be assigned a list
of features and that these features will be tied to the "CAAOsmNovel1"
feature as its children The "CAAOsmChapter" features will no longer
exist independently of "CAAOsmNovel1": if this "parent"
feature is ever deleted, so are the "children" features. Moreover, the
"CAAOsmChapter" features cannot be aggregated to any other
"parent" feature.
CATISpecAttrAccess *piSpecAttrAccessOnNov1 = NULL; rc = piNovelInst1 -> QueryInterface(IID_CATISpecAttrAccess, (void**) &piSpecAttrAccessOnNov1); piNovelInst1 -> Release(); if (FAILED(rc)) { (Process ERROR: Release pointers and return.) } piSpecAttrAccessOnNov1 -> SetSpecObject(piKeyNovelChapter, piChaptInst1); piSpecAttrAccessOnNov1 -> SetSpecObject(piKeyNovelChapter, piChaptInst2); piSpecAttrAccessOnNov1 -> SetSpecObject(piKeyNovelChapter, piChaptInst3); piChaptInst2 -> Release(); piChaptInst3 -> Release(); |
Using a CATISpecAttrAccess pointer based on "CAAOsmNovel1",
the list of "NovelChapter" is valuated using SetSpecObject
to which we pass a handle to the attribute key of the novel chapter that we
retrieved on the "CAAOsmNovel" StartUp and the CATISpecObject
handle to the feature instance of the different chapters to be aggregated by
"CAAOsmNovel1".
Note that piChaptInst1
is not yet released because it will be
used later.
[Top]
int ListSize = piSpecAttrAccessOnNov1 -> GetListSize(piKeyNovelChapter); cout << "The Novel chapter titles (" << ListSize <<") are: " << endl; for ( int i=1 ; i <= ListSize ; i++ ) { CATISpecObject *piNovelChapter = piSpecAttrAccessOnNov1 -> GetSpecObject(piKeyNovelChapter,i); ... CATISpecAttrAccess *piSpecAttrAccessOnNovChapt = NULL; rc = piNovelChapter -> QueryInterface(IID_CATISpecAttrAccess, (void**) &piSpecAttrAccessOnNovChapt); piNovelChapter -> Release(); piNovelChapter = NULL ; ... cout << piSpecAttrAccessOnNovChapt -> GetString(piKeyChapterTitle).CastToCharPtr() << endl; iSpecAttrAccessOnNovChapt -> Release(); piSpecAttrAccessOnNovChapt = NULL ; } piSpecAttrAccessOnNov1 -> Release(); piSpecAttrAccessOnNov1 = NULL ; piKeyChapterTitle -> Release(); piKeyChapterTitle = NULL ; piKeyNovelChapter -> Release(); piKeyNovelChapter = NULL ; |
In order to scan through a list of feature attributes, we use
GetListSize
to retrieve the size of the list. Within
the loop, GetSpecObject
the ieme feature attribute and GetString
(or GetInteger
, etc.) returns the value of the attribute itself.
[Top]
CATISpecObject *piChaptInst1Father = piChaptInst1 -> GetFather(); if (NULL != piChaptInst1Father) { cout << "The 'ChapterInst1' parent feature is " << endl; cout << piChaptInst1Father -> GetName().ConvertToChar() << endl; } piChaptInst1Father -> Release(); piChaptInst1 -> Release(); |
The "parent" of any given instance of "CAAOsmChapter"
that has been aggregated to "CAAOsmNovel1" is
"CAAOsmNovel1". We use the GetFather
method of CATISpecObject
to retrieve a handle to the parent of a given "CAAOsmChapter"
instance. Then, we use the GetName
method of CATISpecObject
to retrieve its name. Therefore, the trace comes out to be:
The 'ChapterInst1' parent feature is CAAOsmNovel1
[Top]
Before proceeding to save the document, be sure to release any remaining pointers that will no longer be used:
piRootContainer -> Release(); piCatalogOnContainer -> Release(); |
See the referenced article [4] for a detailed description of the steps to go through when saving a document.
[Top]
This use case has demonstrated how to use aggregated attributes. Specifically, it has illustrated:
AccessCatalog
global functionRetrieveSU
method of CATICatalogGetAttrKey
method of CATISpecAttrAccessInstanciate
method of CATISpecObjectSet
..."
methods of CATISpecAttrAccesstk_list
tk_component
attributes (aggregated features) of another feature using the SetSpecObject
method of CATISpecAttrAccessGetSpecObject
and GetString
methods of CATISpecAttrAccessGetFather
and GetName
methods of CATISpecObject[Top]
[1] | Feature Modeler Conceptual Overview |
[2] | Creating StartUps in Catalogs |
[3] | Building and Launching a CAA V5 Use Case |
[4] | Creating a New Document |
[Top] |
Version: 1 [Feb 2000] | Document created |
Version: 2 [Nov 2000] | Document modified |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.