Geometric Modeler |
Topology |
How to Use the Topological JournalReading data and creating the journal of a sequence of topological operations |
Use Case |
AbstractThe journal describes the topological modifications brought to the input bodies to get the resulting body during a topological operation. The journal is filled under request by the topological operators. The use case proposes a way to define a topological operator by chaining a sequence of topological operators. In this sequence, data necessary to operations are read in the journal of previous operations. The journal of the global operation is filled. |
In this use case, you learn how to create a new topological operator (CAATopStiffner) by chaining several CGM topological operators. In the sequence,
Meanwhile, the use of the some topological operators is detailed such as:
See "Overview of the Topological Operators" [3] to have the general scheme of the topological operators and other use examples.
[Top]
A topological operator operates on topological objects to create new topological objects. Most of the time, these topological objects are bodies (a body is a set of connected (or not) volumes, faces, edges and vertices [1]). A topological operator does never modify the input bodies: the resulting body is a new one, but it can share cells with the input bodies, if these cells are not touched by the operation. This is called the smart concept [2]. On request, the operator can describe the way to go from the initial objects to the resulting body. This information is then put by each operator into a topological journal.
The topological journal [4] records the creation, modification and deletion of the faces, free edges and free vertices of topological objects. A free edge is an edge bounding at most one face, and a free vertex is a vertex bounding at most one edge. In fact, it is sufficient to follow the modifications of these cells to know how the whole body is modified. The journal is attached to any topological or geometric operator that operates on topological objects.
This journal is transient. You have to create it before its use and delete it when you have finished.
As said, each topological operator is able to write the journal corresponding to its operation. So that the journal of the new operator is the concatenation of the journals of each called CGM operator, as demonstrated in the use case.
[Top]
CAATopJournal is a use case of the CAATopologicalOperators.edu framework that illustrates TopologicalOperators framework capabilities.
[Top]
The use case defines a new topological operator CAATopStiffener, that follows the general scheme of the topological operators:
This operator defines a stiffener between two thin cylinder bodies ("wings") as displayed on Fig.1.
[Top]
To launch CAATopJournal, you will need to set up the build time environment, then compile CAATopJournal.m and CAATopOperator.m along with its prerequisites, set up the run time environment, and then execute the use case [5].
If you simply type CAATopJournal with no argument, the use case executes, but doesn't save the result in an NCGM file. If you want to save this result, provide the full pathname of the NCGM file to create. For example:
With Windows CAATopJournal e:\ExJournal.NCGM
With UNIX CAATopJournal /u/ExJournal.NCGM
This NCGM file can be displayed using the CAAGemBrowser use case.
[Top]
The CAATopJournal use case is made of a main named CAATopJournal.cpp located in the CAATopJournal.m module of the CAATopologicalOperators.edu framework:
Windows | InstallRootDirectory\CAATopologicalOperators.edu\CAATopJournal.m\ |
Unix | InstallRootDirectory/CAATopologicalOperators.edu/CAATopJournal.m/ |
where InstallRootDirectory
is the directory where the CAA CD-ROM
is installed.
This main uses the new operator class CAATopStiffener, which header is located in the ProtectedInterfaces directory of the CAATopologicalOperators.edu framework, and which source is located in the CAATopOperator.m module of the CAATopologicalOperators.edu framework:
Windows | InstallRootDirectory\CAATopologicalOperators.edu\CAATopOperator.m\ |
Unix | InstallRootDirectory/CAATopologicalOperators.edu/CAATopOperator.m/ |
[Top]
The CAATopStiffener header declares the new class, the corresponding code implements it and CAATopJournal.cpp is a main to run the new operator.
The use case is divided into the following steps:
[Top]
We first look at the header of the new class.
class ExportedByCAATopOperator CAATopStiffener { public: // deletes virtual ~CAATopStiffener(); // constructs CAATopStiffener (CATGeoFactory * iFactory, CATTopData * iData, CATBody * iFirstLimitBody, CATBody * iSecondLimitBody, CATBody * iSkinBody, CATMathVector iDirection, CATCGMJournalList * iJournal=NULL); // runs int Run(); // gets the result CATBody * GetResult() ; // data private : CATGeoFactory * _piGeomFactory; // the factory CATBody * _piFirstLimitBody; // the first relimiting surface CATBody * _piSecondLimitBody; // the second relimiting surface CATBody * _piSkinBody ; // the profile (containing an open shell) CATMathVector _direction; // the stiffener direction CATTopData * _pData; // the journal and configuration CATBody * _piResultingBody ; // the resulting body }; |
CAATopStiffener uses the general scheme of the topological operators
(create, Run, GetResult, delete), but it does not derive from CATTopOperator:
remember that you must not derive from any CGM operator, as stated by the U1
status of this class. As for a CGM operator also, the journal must be allocated
by the caller in order to be filled by the called operator: in fact, if the
corresponding pointer is NULL inside the operator data _pData
, the
operator does not fill the journal.
The private data contains the necessary data to run the operator such as the direction of the extrusion, the pointer to the limiting bodies, the pointer to the journal or the pointer to the resulting body.
In the use case, the operator does not have any SetXxxx method that tunes it. But one can easily imagine a SetMeanDirection method, that computes the normal to the mean plane of SkinBody to define the extrusion direction for example.
The constructor simply fills in the private data of the class, except the resulting body, that will be created in the Run method.
CAATopStiffener::CAATopStiffener (CATGeoFactory * iFactory, CATTopData * iData, CATBody * iFirstLimitBody, CATBody * iSecondLimitBody, CATBody * iSkinProfile, CATMathVector iDirection, CATCGMJournalList * iJournal) { _piGeomFactory = iFactory; _piFirstLimitBody = iFirstLimitBody; _piSecondLimitBody= iSecondLimitBody; _piSkinBody = iSkinProfile; _direction = iDirection; _pData = iData; _piResultingBody = NULL; } |
The GetResult method returns the pointer to the created body.
CATBody * CAATopStiffener::GetResult() { CATBody * piReturned = _piResultingBody; _piResultingBody = NULL; // GetResult must only be called once return (piReturned); } |
Notice that once read, the life cycle of the body is taken into account by the caller: the caller must remove it from the factory (CATICGMContainer::Remove) if it does not want to keep it. As any topological operator, GetResult must be only called once.
The destructor removes the created body, if it is created and never retrieved:
CAATopStiffener::~CAATopStiffener() { // if the resulting body is created, and is never retrieved (GetResult), deletes it if(NULL != _piResultingBody) _piGeomFactory->Remove(_piResultingBody, CATICGMContainer::RemoveDependancies); _piResultingBody = NULL; _piGeomFactory = NULL; _piFirstLimitBody = NULL; _piSecondLimitBody= NULL; _piSkinBody = NULL; _pData = NULL; } |
We can now concentrate on the important part of the operator: the Run method, that performs the following:
[Top]
These inputs have been set by the constructor. One just checks that
[Top]
A prism operator is first created with the ::CATCreateTopPrism global function.
// --------- Creates the operator // double offset = 0.; CATMathDirection direction (_direction); // Journal and configuration // Constructs a topdata from the input CATTopData internalTopdata(*_pData); // Gets the associated configuration CATSoftwareConfiguration * pConfig = internalTopdata.GetSoftwareConfiguration(); // To use it to create a journal that will be embedded in the created internalTopdata CATCGMJournalList* pJournal = new CATCGMJournalList(pConfig,NULL); // sets the journal for the internal operations internalTopdata.SetJournal(pJournal); // and now creates the operator CATTopPrism *pPrismOp = ::CATCreateTopPrism (piGeomFactory, &internalTopdata, piSkinBody, &direction, offset, // non significative: the limits are defined later offset); // non significative: the limits are defined later if (NULL==pPrismOp) return (1); |
A specific journal is created inside the operator: in fact, this journal
is needed by the algorithm of CAATopStiffener, as seen later, but not
necessarily asked for by the caller. Moreover, this allows the operator to
modify the input journal (if asked for) only when all its algorithm is done.
The specific journal is allocated and passed to the ::CATCreateTopPrism
global function within the data internalTopData
. It is
independent on the general input journal of the operator, which is stored in
_pData at the CATopStiffener creation. In fact, if the
journal in _pData is not null, pJournal will be copied
inside it to report all the orders of the operators chain.
Notice that the journal is always versioned [6] by a software configuration, retrieved from the input CATTopData.
The geometry factory, the skin body to extrude and the extrusion direction are set at the CAATopStiffener creation. In case of "until" limits, the start and end offset are not significative: the limits are in fact tuned by the SetLimit method.
// --------- Sets options // // Sets the relimiting body pPrismOp->SetTrim(piFirstLimitBody); // Asks for the Boolean union with the relimiting body pPrismOp->SetOperation(CatBoolUnion); // Asks to also retrieve the result of the Booleean operation pPrismOp->SetResultMode(TRUE); // Sets the until limits: first limit pPrismOp->SetLimit(CatLimStart, // first limit CatLimUntil, // until option TRUE , // same orientation as the direction offset, // non significative (until limits) piFirstLimitBody, // the limiting geometry: here a body piFirstLimitBody, // must be the same as the previous one CatPropagSingle); // keep to this value // Sets the until limits: second limit pPrismOp->SetLimit(CatLimEnd, CatLimUntil, TRUE , offset, piSecondLimitBody, piSecondLimitBody, CatPropagSingle); |
The prism must be delimited on one of the limiting bodies (SetTrim), and there must be a Boolean union operation between the delimiting body and the computed prism (SetOperation). Moreover, we want to recover the result of this Boolean operation (SetResultMode set to TRUE). SetLimit must be called for each limit (CatLimStart, CATLimEnd), to ask an "until" limit (CatLimUntil) on each side. Notice that each limit can have a different behavior: one limit "until", the other defined by an offset from the profile. The prism operator can now be run.
// --------- Runs CATTry { pPrismOp ->Run(); } CATCatch(CATError,error) { cout << (error->GetNLSMessage()).ConvertToChar() << endl; rc = 20; } CATEndTry if (rc!=0) CAAErrorTopStif1(rc,pJournal) // --------- Gets the resulting body // CATBody * piMainBody1=NULL; piMainBody1 = pPrismOp->GetBooleanResult(); // gets the prism before the union CATBody * piWithoutOperation = pPrismOp->GetResult(); // gets the journal of the boolean operation CATCGMJournalList * pBooleanJournal = pPrismOp->GetBooleanJournal(); if (NULL==piMainBody1 || NULL==pBooleanJournal || NULL==piWithoutOperation) { rc = 20; CAAErrorTopStif2(rc,pJournal,piGeomFactory,pPrismOp,piMainBody1,piWithoutOperation) } |
As the Run method can throw errors, these are caught by the macros CATTry, CATCatch, CATEndTry. The CAAErrorTopStifx macros are defined in the use case to clean the model in case of return: they free the allocations and delete the intermediate created bodies and geometry, but are not detailed in this article.
The GetResult method returns the prism before its union with the limiting bodies, while the GetBooleanResult returns the body corresponding to the result after the union. In the same way, pJournal contains the modifications corresponding to the prism creation, whereas GetBooleanJournal returns a new created journal containing the modifications relative to the Boolean operation.
[Top]
In order to recover the faces on which circles have been drawn on Fig. 1, we first search the longest edge of the face of SkinBody.
This edge could also be put as an input argument, or with a SetXxx method to the operator! Here, this gives us the opportunity to use a CATBoundaryIterator class to retrieve the edges of a face.
The iterator is created by the CATCell::CreateBoundaryIterator and skips from one boundary cell to the other one with the CATBoundaryIterator::Next method. The approximate length of an edge is computed with the CATEdge::CalcLength method. After comparing the lengths of the first two edges, we can easily deduce the two long sides, as the profile is rectangular.
The written code is not generic: by assumption, the face is rectangular.
[Top]
The topological journal is made of CATCGMJournalItem (unitary order) and CATCGMJournalList (list of items). Each item has a type such as
To explore the topological journal, high level methods are provided, such as FindFirsts and FindLasts, that recursively scan the journal to retrieve:
These methods can scan along a type of item, or several types (see the ThroughCreateAndModify
value)
Example: Let the following journal sequence: F1 -> F2 -> F3 -> F4 -> F5
FindFirsts from F3 gives F1, and FindLasts from F3 gives F5.
// Retrieves all the objects created or modified from piHeight1 // first, in pJournal CATLISTP(CATGeometry) pFaces; pJournal->FindLasts (piHeight1,pFaces,ThroughCreateAndModify); CATFace * piFromHeight1=NULL; int nbresult = pFaces.Size(); // Retrieves the object that is a face. for (int i=1 ; (i <= nbresult) && (piFromHeight1 == NULL) ; i++) { if (pFaces[i]->IsATypeOf(CATFaceType)) { piFromHeight1=(CATFace *)pFaces[i];} } // now, in pBooleanJournal pFaces.RemoveAll(); // voids the list before a new use pBooleanJournal->FindLasts (piFromHeight1,pFaces,ThroughModify); CATFace * piBooleanFromHeight1=NULL; nbresult = pFaces.Size(); // Retrieves the object that is a face. for (i=1 ; (i <= nbresult) && (piBooleanFromHeight1 == NULL) ; i++) { if (pFaces[i]->IsATypeOf(CATFaceType)) { piBooleanFromHeight1=(CATFace *)pFaces[i];} } if (NULL==piBooleanFromHeight1) { rc =21; CAAErrorTopStif3(...) } |
|
[Top]
// Gets the surface of the face CATOrientation orientation; CATSurface * piSurfaceFromHeight = piBooleanFromHeight1->GetSurface(&orientation); if (NULL==piSurfaceFromHeight) { rc =1; CAAErrorTopStif3(...) } // Estimates the center of the face CATSurParam centerParam; piFromHeight1->EstimateCenterParam (centerParam); // Creates a circle on the surface CATPCircle * piPCircle1 = piGeomFactory -> CreatePCircle( height/3., centerParam, piSurfaceFromHeight); if (NULL==piPCircle1) { rc =1; CAAErrorTopStif3(...) } |
The surface is retrieved with the CATFace::GetSurface method. The center of the circle is put at the "center" of the face, which is only an approximate point. The created circle is a CATPCircle, because it is a circle in the space of the surface.
The way to define a circle on the other face is similar and not detailed here.
[Top]
On must first define one journal of the two operations: the prism creation (pJournal) and the Boolean operation (pBooleanJournal).
// Copies in a single journal and deletes the unused body pBooleanJournal-> Duplicate(pJournal); piGeomFactory->Remove(piWithoutOperation,pJournal); piWithoutOperation=NULL; |
pBooleanJournal is duplicated in pJournal. pBooleanJournal will be directly deleted at the CATTopPrism deletion, while Journal now contains all the items of both operations. Then, the prism before union is removed with the Remove method of CATICGMContainer, with the journal as input: in this case all deletion items will be logged if necessary.
Now, the face of the wing is searched for: this face has been modified by the Boolean operation: a hole is created. The word "modified" is a shorter way to tell that in the resulting body, a new face is created with a hole corresponding to the trace of the prism.
CATLISTP(CATCell) listCells; piFirstLimitBody->GetAllCells(listCells,2); // gets all the faces of FirstlimitBody nbCells = listCells.Size(); CATFace * piFromBody1=NULL; int iok=0; for (i=1;(i <= nbCells) ;i++) { pFaces.RemoveAll(); // voids the list pBooleanJournal -> FindLasts (listCells[i],pFaces,ThroughModify); nbresult = pFaces.Size(); for (int j=1; (j <= nbresult) && (piFromBody1 == NULL) ; j++) { if (pFaces[j]->IsATypeOf(CATFaceType) // searches for a face && pFaces[j] != listCells[i] ) // different from the initial one { piFromBody1=(CATFace *)pFaces[j]; iok = iok + 1; } } } if (1!=iok) { rc=30; CAAErrorTopStif5(...) } // ---------- Deletes the operator delete pPrismOp; pPrismOp = NULL; |
|
[Top]
A filleting operation is defined by affecting a (possibly variable) radius to edges:
CATDynFilletRadius * pRadius = new CATDynFilletRadius( 5., // radius value NULL, // the cell on which the radius is defined (for variable radius) NULL, // The ratio of the edge length defining the point (for variable radius) NULL); // must be kept to NULL if (NULL==pRadius) { rc=1; CAAErrorTopStif5(...) } CATLISTP(CATDynFilletRadius) listRadius; listRadius.Append(pRadius); |
Now, the ribbon is defined.
The edges to fillet are common (GetCommonBorderCells) to the face with hole FromBody1 and the faces of the prism BooleanFromHeight1 and BooleanFromHeight2. These non connected edges are appended to the list used to define the ribbon. The CATDynFilletRibbon::SetSegmentationMode option indicates that the computed ribbon must be delimited on the main body.
The CATDynFillet operator can now be created.
// ----------- Creates the operator // CATDynFillet * pFilletOp = ::CATCreateDynFillet(piGeomFactory,&internalTopdata,piMainBody1,pJournal); if (NULL==pFilletOp) { rc=1; CAAErrorTopStif7(...) } //---- Appends the ribbon pFilletOp ->Append(pRibbon); //---- Runs CATTry { pFilletOp ->Run(); } CATCatch(CATError,error) { cout << (error->GetNLSMessage()).ConvertToChar() << endl; rc=20; CAAErrorTopStif7(...) } CATEndTry //---- Gets the resulting body CATBody * piMainBody2 = pFilletOp->GetResult(); if (NULL==piMainBody2) { rc=1; CAAErrorTopStif7(...) } //---- Deletes the operator delete pFilletOp; pFilletOp = NULL; if (NULL != pRadius) delete pRadius; pRadius = NULL; if (NULL != pRibbon) delete pRibbon; pRibbon = NULL; //---- Deletes the unused body piGeomFactory->Remove(piMainBody1,pJournal); _piResultingBody = piMainBody2; |
Notice the general scheme of the operator. To use it:
pJournal is re-used here, so that the filleting operator directly puts its items inside it: at the end of the operation, pJournal contains the items of the prism creation, the Boolean operation and the filleting operation. In the same way, the GetResult method retrieves MainBody2, the body representing the result of the three operations. MainBody1 is now useless, and is removed by the factory: the items corresponding to this deletion are put in pJournal, as argument of the Remove method.
[Top]
// Fills the output journal if needed CATCGMJournalList * pDataJournal = NULL; pDataJournal=_pData->GetJournal(); if (NULL!= pDataJournal) { pJournal->Duplicate(pDataJournal); // duplicates the internal journal inside the input journal } delete pJournal; // deletes the internal journal |
As seen in step 2, pJournal was internally allocated to contain the items of the prism, Boolean union and filleting operations. If the caller of CAATopStiffener operator asks for the report of the modifications, the items must be copied inside the journal allocated by the caller, which address is stored in _pData. pJournal can then be deallocated.
[Top]
To use the new operator, one must go through the following steps:
[Top]
The geometry factory (CATGeoFactory) creates and manages all the CATICGMObject: it creates the points, curves, surfaces, and bodies, and removes them [7].
The CATGeoFactory creation itself is done by the global function ::CATCreateCGMContainer.
Notice that the factory can be defined by reading a NCGM file that was previously stored. In that case, the global function ::CATLoadCGMContainer must be used.
CATGeoFactory* piGeomFactory = ::CATCreateCGMContainer() ; if (NULL==piGeomFactory) return (1); |
[Top]
These bodies are defined as a cylinder skin body extruded along a direction. To create them, one must
CATMathDirection z(0.,0.,1.); CATMathAxis axis1(CATMathPoint(0.,0.,-120.), CATMathVector(0.,1.,0.), z, CATMathVector(1.,0.,0.)); double radius = 140.; double axisStart= -30.; double axisEnd = 30.; double angleStart = CATPIBY2-0.3; double angleEnd = CATPIBY2+0.3; CATCylinder * piCylinder1 = piGeomFactory->CreateCylinder (axis1,radius,axisStart,axisEnd,angleStart,angleEnd); if (NULL == piCylinder1) { ::CATCloseCGMContainer(piGeomFactory); return (1); } |
A geometric object as a cylinder is created by the CATGeoFactory.
axisStart and axisEnd define the limitation of the surface
along the cylinder axis, angleStart and angleEnd define
the limitation around the axis cylinder. The angle are measured in radians, CATPI
and other related values are defined in CATMathConstant.h.
// Creates a skin body // first defines an open configuration for the operator CATSoftwareConfiguration * pConfig = new CATSoftwareConfiguration(); // defines the data of the operator: configuration + journal CATTopData topdata(pConfig,NULL); // an open configuration and a NULL journal // defines the limits to take into account CATSurLimits limits; piCylinder1->GetLimits(limits); // now creates the operator CATTopSkin * pSkinOp = ::CATCreateTopSkin(piGeomFactory,&topdata,piCylinder1,&limits); if (NULL==pSkinOp) { ::CATCloseCGMContainer(piGeomFactory); return (1); } // Runs pSkinOp->Run(); // Gets the resulting body CATBody * piFirstCylinderBody = pSkinOp->GetResult(); if (NULL==piFirstCylinderBody) { ::CATCloseCGMContainer(piGeomFactory); return (1); } // Deletes the operator delete pSkinOp; pSkinOp = NULL; |
The operator configuration is the level of software you want to use to
run this operator. By default, define an open configuration as in this use
case to run with the current level. Moreover here, the pointer to the
journal is set to NULL
in the operator data. So that the
journal is not filled. The configuration must be released after use. Here, it is
released
after the call to the last operator.
CATTopSkin can create a skin body from a list a curves on surface, or directly on the boundaries of a surface. Here the surface is the limited cylinder. CATTopSkin is invoked according to the general scheme, that:
CATCreateTopSkin
The created SkinBody is now extruded to create a prism with CATTopPrism.
CATCGMJournalList * pJournal = NULL; CATTopPrism *pPrismOp = ::CATCreateTopPrism (piGeomFactory, &topdata, piFirstCylinderBody, &z, 0., // limit1 2., // limit2 pJournal); if (NULL==pPrismOp) { ::CATCloseCGMContainer(piGeomFactory); return (1); } pPrismOp->Run(); CATBody* piFirstLimitBody = pPrismOp->GetResult(); if (NULL==piFirstLimitBody) { ::CATCloseCGMContainer(piGeomFactory); return (1); } delete pPrismOp; pPrismOp=NULL; |
Once again, the same steps are used, that:
As the body to extrude is a skin body, FirstLimitBody is a volume body. If the body to extrude were a wire body, the result would be a skin body. Other types of prism operations can be described, especially "until" operations: the limits of the prism are reached when encountering another body. This is detailed in the CAATopJournal section.
The other limiting body is created in the same way, and this is not detailed here.
[Top]
The cylinder skin body was created using a surface, here the skin body is defined by giving a list of four segments on a geometric plane.
No assumption can be done on the parameterization of the geometric objects. The parameters on the plane are evaluated with the CATSurface::GetParam method, from 3D points that are known to be on the plane. This method can be called because the plane is a canonical object, and the points are already on it. If one of these conditions were not filled, it would be mandatory to call the CATProjectionPtSur geometric operator.
CATTopSkin needs
// Creates the operator pSkinOp = CATCreateTopSkin (piGeomFactory, &topdata, nbPCurves, aPCurves, aLimits, aOrientations); if (NULL==pSkinOp) { ::CATCloseCGMContainer(piGeomFactory); return (1); } // Runs pSkinOp->Run(); // Gets the resulting body CATBody * piSkinBody = pSkinOp->GetResult(); if (NULL==piSkinBody) { ::CATCloseCGMContainer(piGeomFactory); return (1); } // Deletes the operator delete pSkinOp; pSkinOp = NULL; |
[Top]
//--- Creates the operator CAATopStiffener *pStiffOp = new CAATopStiffener (piGeomFactory, &topdata, piFirstLimitBody, piSecondLimitBody, piSkinBody, z, pJournal); if (NULL==pStiffOp) { ::CATCloseCGMContainer(piGeomFactory); return (1); } //--- Runs rc = pStiffOp->Run(); if (NUL!=rc) { ::CATCloseCGMContainer(piGeomFactory); return (rc); } //--- Gets the resulting body CATBody * piMainBody1=NULL; piMainBody1 = pStiffOp->GetResult(); if (NULL==piMainBody1) { ::CATCloseCGMContainer(piGeomFactory); return (1); } //--- Deletes the operator delete pStiffOp; pStiffOp = NULL; // Releases the configuration pConfig->Release(); |
The new operator is used as a CGM operator with the steps that creates, runs, gets the result, and deletes.
The software configuration is also released, because it is no more used.
[Top]
To save the model in a file, the ::CATSaveCGMContainer global function is used. Notice that in the sample, the save is conditioned by an input parameter representing the file inside which the model must be saved.
The sample ends with the closure of the geometry factory, done by the ::CATCloseCGMContainer global function.
if(1==toStore) { #ifdef _WINDOWS_SOURCE ofstream filetowrite(pfileName, ios::binary ) ; #else ofstream filetowrite(pfileName,ios::out,filebuf::openprot) ; #endif ::CATSaveCGMContainer(piGeomFactory,filetowrite); filetowrite.close(); } // // Closes the container // ::CATCloseCGMContainer(piGeomFactory); |
[Top]
The journal follows the topological modification from the input bodies (that are never modified) to the output body. This journal is read to recover topological entities, that can be later used in other topological operations.
New operator classes can be developed, by chaining several topological operations. In this case, the corresponding journal is the concatenation of the journal of each operator. If an intermediate body is removed, this must be declared in the journal.
[Top]
Version: 1.1 [Oct 2000] | Operator configuration |
Version: 1 [May 2000] | Document created |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.