![]() |
Open CASCADE Technology
6.7.1
|
This manual explains how to use the Open CASCADE Application Framework (OCAF). It provides basic documentation on using OCAF. For advanced information on OCAF and its applications, see our offerings on our web site at www.opencascade.org/support/training/
OCAF (the Open CASCADE Application Framework) is a RAD (Rapid Application Development) framework used for specifying and organizing application data. To do this, OCAF provides:
Using OCAF, the application designer concentrates on the functionality and its specific algorithms. In this way, he avoids architectural problems notably implementing Undo-redo and saving application data.
In OCAF, all of the above are already handled for the application designer, allowing him to reach a significant increase in productivity.
In this respect, OCAF is much more than just one toolkit among many in the CAS.CADE Object Libraries. Since it can handle any data and algorithms in these libraries - be it modeling algorithms, topology or geometry - OCAF is a logical supplement to these libraries.
The table below contrasts the design of a modeling application using object libraries alone and using OCAF.
Table 1: Services provided by OCAF
Development tasks | Comments | Without OCAF | With OCAF |
---|---|---|---|
Creation of geometry | Algorithm Calling the modeling libraries | To be created by the user | To be created by the user |
Data organization | Including specific attributes and modeling process | To be created by the user | Simplified |
Saving data in a file | Notion of document | To be created by the user | Provided |
Document-view management | To be created by the user | Provided | |
Application infrastructure | New, Open, Close, Save and Save As File menus | To be created by the user | Provided |
Undo-Redo | Robust, multi-level | To be created by the user | Provided |
Application-specific dialog boxes | To be created by the user | To be created by the user |
The relationship between OCAF and the Open CASCADE Technology (OCCT) Object Libraries can be seen in the image below.
In the image, the OCAF (Open CASCADE Application Framework) is shown with black rectangles and OCCT Object Libraries required by OCAF are shown with white rectangles.
The subsequent chapters of this document explain the concepts and show how to use the services of OCAF.
In most existing geometric modeling systems, the data structure is shape driven. They usually use a brep model, where solids and surfaces are defined by a collection of entities such as faces, edges etc., and by attributes such as application data. These attributes are attached to the entities. Examples of application data include:
A shape, however, is inevitably tied to its underlying geometry. And geometry is highly subject to change in applications such as parametric modeling or product development. In this sort of application, using a brep (boundary representation) data structure proves to be a not very effective solution. A solution other than the shape must be found, i.e. a solution where attributes are attached to a deeper invariant structure of the model. Here, the topology itself will be one attribute among many.
In OCAF, data structure is reference key-driven. The reference key is implemented in the form of labels. Application data is attached to these labels as attributes. By means of these labels and a tree structure they are organized in, the reference key aggregates all user data, not just shapes and their geometry. These attributes have similar importance; no attribute is master in respect of the others.
The reference keys of a model - in the form of labels - have to be kept together in a single container. This container is called a document.
OCAF documents are in turn managed by an OCAF application, which is in charge of:
Apart from their role as a container of application data, documents can refer to each other; Document A, for example, can refer to a specific label in Document B. This functionality is made possible by means of the reference key.
Inside a document, there is a data framework, a model, for example. This is a set of labels organized in a tree structure characterized by the following features:
The children of a root label are middle-level labels with tags 1 and 3. These labels are brothers.
List of tags of the right-bottom label is "0:3:4": this label has tag 4, its father (with entry "0:3") has tag 3, father of father has tag 0 (the root label always has "0" entry).
For example, an application for designing table lamps will first allocate a label for the lamp unit (the lamp is illustrated below). The root label never has brother labels, so, for a lot of lamps in the framework allocation, one of the root label sub-labels for the lamp unit is used. By doing so, you would avoid any confusion between table lamps in the data framework. Parts of the lamp have different material, color and other attributes, so, for each sub-unit of the lamp a child label of the lamp label with specified tags is allocated:
Label tags are chosen at will. They are just identifiers of the lamp parts. Now you can refine all units: set to the specified label geometry, color, material and other information about the lamp or it’s parts. This information is placed into special attributes of the label: the pure label contains no data – it is only a key to access data.
The thing to remember is that tags are private addresses without any meaning outside the data framework. It would, for instance, be an error to use part names as tags. These might change or be removed from production in next versions of the application, whereas the exact form of that part might be what you wanted to use in your design, the part name could be integrated into the framework as an attribute.
So, after the user changes the lamp design, only corresponding attributes are changed, but the label structure is maintained. The lamp shape must be recreated by new attribute values and attributes of the lamp shape must refer to a new shape.
The previous figure shows the table-lamps document structure: each child of the root label contains a lamp shape attribute and refers to the sub-labels, which contain some design information about corresponding sub-units.
The data framework structure allows to create more complex structures: each lamp label sub-label may have children labels with more detailed information about parts of the table lamp and its components.
Note that the root label can have attributes too, usually global attributes: the name of the document, for example.
As in the case of the table lamp example above, OCAF documents aggregate a battery of ready-to-use attributes, which represent typical data used in CAD. This data includes not only the Shape attribute, but a wide range of Standard attributes corresponding to the following types:
Documents offer access to the data framework and manage the following items:
The shape attribute implements the functionality of the OCCT topology manipulation:
Several ready-to-use base attributes already exist. These allow operating with simple common data in the data framework (for example: integer, real, string, array kinds of data), realize auxiliary functions (for example: tag sources attribute for the children of the label counter), create dependencies (for example: reference, tree node)....
These attributes allow placing viewer information to the data framework, visual representation of objects and other auxiliary visual information, which is needed for graphical data representation.
Where the document manages the notification of changes, a function manages propagation of these changes. The function mechanism provides links between functions and calls to various algorithms.
The data framework offers a single environment in which data from different application components can be handled.
This allows you to exchange and modify data simply, consistently, with a maximum level of information, and with stable semantics.
The building blocks of this approach are:
As it has been mentioned earlier, the first label in a framework is the root label of the tree. Each label has a tag expressed as an integer value, and a label is uniquely defined by an entry expressed as a list of tags from the root, 0:1:2:1, for example.
Each label can have a list of attributes, which contain data, and several attributes can be attached to a label. Each attribute is identified by a GUID, and although a label may have several attributes attached to it, it must not have more than one attribute of a single GUID.
The sub-labels of a label are called its children. Conversely, each label, which is not the root, has a father. Brother labels cannot share the same tag.
The most important property is that a label’s entry is its persistent address in the data framework.
A tag is an integer, which identifies a label in two ways:
In relative identification, a label’s tag has a meaning relative to the father label only. For a specific label, you might, for example, have four child labels identified by the tags 2, 7, 18, 100. In using relative identification, you ensure that you have a safe scope for setting attributes.
In absolute identification, a label’s place in the data framework is specified unambiguously by a colon-separated list of tags of all the labels from the one in question to the root of the data framework. This list is called an entry. TDF_Tool::TagList allows retrieving the entry for a specific label.
In both relative and absolute identification, it is important to remember that the value of an integer has no intrinsic semantics whatsoever. In other words, the natural sequence that integers suggest, i.e. 0, 1, 2, 3, 4 ... - has no importance here. The integer value of a tag is simply a key.
The tag can be created in two ways:
As the names suggest, in random delivery, the tag value is generated by the system in a random manner. In user-defined delivery, you assign it by passing the tag as an argument to a method.
To append and return a new child label, you use TDF_TagSource::NewChild. In the example below, the argument level2, which is passed to NewChild, is a TDF_Label.
The other way to create a child label from a tag is by user delivery. In other words, you specify the tag, which you want your child label to have.
To retrieve a child label from a tag which you have specified yourself, you need to use TDF_Label::FindChild and TDF_Label::Tag as in the example below. Here, the integer 3 designates the tag of the label you are interested in, and the Boolean false is the value for the argument create. When this argument is set to false, no new child label is created.
The tag gives a persistent address to a label. The label – the semantics of the tag – is a place in the data framework where attributes, which contain data, are attached. The data framework is, in fact, a tree of labels with a root as the ultimate father label (refer to the following figure):
Label can not be deleted from the data framework, so, the structure of the data framework that has been created can not be removed while the document is opened. Hence any kind of reference to an existing label will be actual while an application is working with the document.
Labels can be created on any labels, compared with brother labels and retrieved. You can also find their depth in the data framework (depth of the root label is 0, depth of child labels of the root is 1 and so on), whether they have children or not, relative placement of labels, data framework of this label. The class TDF_Label offers the above services.
To create a new child label in the data framework using explicit delivery of tags, use TDF_Label::FindChild.
You could also use the same syntax but add the Boolean true as a value of the argument create. This ensures that a new child label will be created if none is found. Note that in the previous syntax, this was also the case since create is true by default.
You can retrieve child labels of your current label by iteration on the first level in the scope of this label.
You can also retrieve all child labels in every descendant generation of your current label by iteration on all levels in the scope of this label.
Using TDF_Tool::Entry with TDF_ChildIterator you can retrieve the entries of your current label’s child labels as well.
Retrieving the father label of a current label.
The label itself contains no data. All data of any type whatsoever - application or non-application - is contained in attributes. These are attached to labels, and there are different types for different types of data. OCAF provides many ready-to-use standard attributes such as integer, real, constraint, axis and plane. There are also attributes for topological naming, functions and visualization. Each type of attribute is identified by a GUID.
The advantage of OCAF is that all of the above attribute types are handled in the same way. Whatever the attribute type is, you can create new instances of them, retrieve them, attach them to and remove them from labels, "forget" and "remember" the attributes of a particular label.
To retrieve an attribute from a label, you use TDF_Label::FindAttribute. In the example below, the GUID for integer attributes, and INT, a handle to an attribute are passed as arguments to FindAttribute for the current label.
You can create a new instance of an attribute and retrieve its GUID. In the example below, a new integer attribute is created, and its GUID is passed to the variable guid by the method ID inherited from TDF_Attribute.
To attach an attribute to a label, you use TDF_Label::Add. Repetition of this syntax raises an error message because there is already an attribute with the same GUID attached to the current label.
TDF_Attribute::Label for INT then returns the label attach to which INT is attached.
You can test whether an attribute is attached to a label or not by using TDF_Attribute::IsA with the GUID of the attribute as an argument. In the example below, you test whether the current label has an integer attribute, and then, if that is so, how many attributes are attached to it. TDataStd_Integer::GetID provides the GUID argument needed by the method IsAttribute.
TDF_Attribute::HasAttribute tests whether there is an attached attribute, and TDF_Tool::NbAttributes returns the number of attributes attached to the label in question, e.g. current.
To remove an attribute from a label, you use TDF_Label::Forget with the GUID of the deleted attribute. To remove all attributes of a label, TDF_Label::ForgetAll.
If the set of existing and ready to use attributes implementing standard data types does not cover the needs of a specific data presentation task, the user can build his own data type and the corresponding new specific attribute implementing this new data type.
There are two ways to implement a new data type: create a new attribute (standard approach), or use the notion of User Attribute by means of a combination of standard attributes (alternative way)
In order to create a new attribute in the standard way do the following:
Methods NewEmpty, Restore and Paste are used for the common transactions mechanism (Undo/Redo commands). If you don’t need this attribute to react to undo/redo commands, you can write only stubs of these methods, else you must call the Backup method of the TDF_Attribute class every time attribute fields are changed.
If you use a standard file format and you want your new attributes to be stored during document saving and retrieved to the data framework whenever a document is opened, you must do the following:
If you use the XML format, do the following:
If you decided to use the alternative way (create a new attribute by means of UAttribute and a combination of other standard attributes), do the following:
Choosing the alternative way of implementation of new data types allows to forget about creating persistence classes for your new data type. Standard persistence classes will be used instead. Besides, this way allows separating the data and the methods for access to the data (interfaces). It can be used for rapid development in all cases when requirements to application performance are not very high.
Let’s study the implementation of the same data type in both ways by the example of transformation represented by gp_Trsf class. The class gp_Trsf defines the transformation according to the type (gp_TrsfForm) and a set of parameters of the particular type of transformation (two points or a vector for translation, an axis and an angle for rotation, and so on).
Standard documents offer ready-to-use documents containing a TDF-based data framework. Each document can contain only one framework.
The documents themselves are contained in the instantiation of a class inheriting from TDocStd_Application. This application manages the creation, storage and retrieval of documents.
You can implement undo and redo in your document, and refer from the data framework of one document to that of another one. This is done by means of external link attributes, which store the path and the entry of external links.
To sum up, standard documents alone provide access to the data framework. They also allow you to:
As a container for your data framework, you need a document, and your document must be contained in your application. This application will be a class inheriting from TDocStd_Application.
To create an application, use the following syntax.
Note that MyApplication_Application is a class, which you have to create and which will inherit from TDocStd_Application.
To the application which you declared in the previous example (4.2.1), you must add the document doc as an argument of TDocStd_Application::NewDocument.
To retrieve the application containing your document, you use the syntax below.
The document contains your data framework, and allows you to retrieve this framework, recover its main label, save it in a file, and open or close this file.
To access the main label in the data framework, you use TDocStd_Document::Main as in the example below. The main label is the first child of the root label in the data framework, and has the entry 0:1.
To retrieve the document from a label in its data framework, you use TDocStd_Document::Get as in the example below. The argument label passed to this method is an instantiation of TDF_Label.
If in your document you use only standard attributes (from the packages TDF, TDataStd, TNaming, TFunction, TPrsStd and TDocStd), you just do the following steps:
Example
In order to set the paths for these files it is necessary to set the environments: CSF_PluginDefaults and CSF_NewFormatDefaults. For example, set the files in the directory MyApplicationPath/MyResources:
Once these steps are taken you may run your application, create documents and Save/Open them. These resource files already exist in the OCAF (format "Standard").
If you use your specific attributes from packages, for example, P-, M- and TMyAttributePackage, see "Specific attribute creation" on page 20; you must take some additional steps for the new plugin implementation:
To open the document from a file where it has been previously saved, you use TDocStd_Application::Open as in the example below. The arguments are the path of the file and the document saved in this file.
External links refer from one document to another. They allow you to update the copy of data framework later on.
To copy a document with a possibility of updating it later, you use TDocStd_XLinkTool::CopyWithLink.
Now the target document has a copy of the source document. The copy also has a link in order to update the content of the copy if the original changes.
In the example below, something has changed in the source document. As a result, you need to update the copy in the target document. This copy is passed to TDocStd_XLinkTool::UpdateLink as the argument target.
You can also create a copy of the document with no link between the original and the copy. The syntax to use this option is TDocStd_XLinkTool::Copy; the copied document is again represented by the argument target, and the original – by source.
OCAF shape attributes are used for topology objects and their evolution access. All topological objects are stored in one TNaming_UsedShapes attribute at the root label of the data framework. This attribute contains a map with all topological shapes used in a given document.
The user can add the TNaming_NamedShape attribute to other labels. This attribute contains references (hooks) to shapes from the TNaming_UsedShapes attribute and an evolution of these shapes. The TNaming_NamedShape attribute contains a set of pairs of hooks: to the Old shape and to a New shape (see the following figure). It allows not only to get the topological shapes by the labels, but also to trace the evolution of the shapes and to correctly update dependent shapes by the changed one.
If a shape is newly created, then the old shape of a corresponding named shape is an empty shape. If a shape is deleted, then the new shape in this named shape is empty.
Different algorithms may dispose sub-shapes of the result shape at the individual labels depending on whether it is necessary to do so:
TNaming_NamedShape may contain a few pairs of hooks with the same evolution. In this case the topology shape, which belongs to the named shape is a compound of new shapes.
Consider the following example. Two boxes (solids) are fused into one solid (the result one). Initially each box was placed to the result label as a named shape, which has evolution PRIMITIVE and refers to the corresponding shape of the TNaming_UsedShapes map. The box result label has a material attribute and six child labels containing named shapes of Box faces.
Named shapes, which contain information about modified faces, belong to the fuse result sub-labels: sub-label with tag 1 – modified faces of the first box, sub-label with tag 2 – generated faces of the box 2.
This is necessary and sufficient information for the functionality of the right naming mechanism: any sub-shape of the result can be identified unambiguously by name type and set of labels, which contain named shapes:
After any modification of source boxes the application must automatically rebuild the naming entities: recompute the named shapes of the boxes (solids and faces) and fuse the resulting named shapes (solids and faces) that reference to the new named shapes.
When using TNaming_NamedShape to create attributes, the following fields of an attribute are filled:
Only pairs of shapes with equal evolution can be stored in one named shape.
The class TNaming_Builder allows you to create a named shape attribute. It has a label of a future attribute as an argument of the constructor. Respective methods are used for the evolution and setting of shape pairs. If for the same TNaming_Builder object a lot of pairs of shapes with the same evolution are given, then these pairs would be placed in the resulting named shape. After the creation of a new object of the TNaming_Builder class, an empty named shape is created at the given label.
You can use TNaming_NamedShape class to get evolution of this named shape (method TNaming_NamedShape::Evolution()) and "value" of the named shape – compound of new shapes of all pairs of this named shape (method TNaming_NamedShape::Get()).
More detailed information about the contents of the named shape or about the modification history of a topology can be obtained with the following:
One of user interfaces for topological naming resources is the TNaming_Selector class. You can use this class to:
Selector places a new named shape with evolution SELECTED to the given label. By the given context shape (main shape, which contains a selected sub-shape), its evolution and naming structure the selector creates a "name" of the selected shape – unique description how to find a selected topology.
After any modification of a context shape and updating of the corresponding naming structure, you must call the TNaming_Selector::Solve method. If the naming structure is right, then the selector automatically updates the selected shape in the corresponding named shape, else it fails.
The class TNaming_Tool provides a toolkit to read current data contained in the attribute.
If you need to create a topological attribute for existing data, use the method NamedShape.
There are several ready-to-use attributes, which allow creating and modifying attributes for many basic data types. They are available in the packages TDataStd, TDataXtd and TDF. Each attribute belongs to one of four types:
All of these attributes inherit class TDF_Attribute, so, each attribute has its own GUID and standard methods for attribute creation, manipulation, getting access to the data framework.
To access the GUID of an attribute, you can use two methods:
It is usual to create standard named methods for the attributes:
Standard visualization attributes implement the Application Interactive Services (see Open CASCADE Technology Visualization User’s Guide) in the context of Open CASCADE Technology Application Framework. Standard visualization attributes are AISViewer and Presentation and belong to the TPrsStd package.
The class TPrsStd_AISViewer allows you to define an interactive viewer attribute. There may be only one such attribute per one data framework and it is always placed to the root label. So, it could be set or found by any label ("access label") of the data framework. Nevertheless the default architecture can be easily extended and the user can manage several Viewers per one framework by himself.
To initialize the AIS viewer as in the example below, use method Find.
The class TPrsStd_AISPresentation allows you to define the visual presentation of document labels contents. In addition to various visual fields (color, material, transparency, "isDisplayed", etc.), this attribute contains its driver GUID. This GUID defines the functionality, which will update the presentation every time when needed.
The abstract class TPrsStd_Driver allows you to define your own driver classes. Simply redefine the Update method in your new class, which will rebuild the presentation.
If your driver is placed to the driver table with the unique driver GUID, then every time the viewer updates presentations with a GUID identical to your driver’s GUID, the Update method of your driver for these presentations must be called:
As usual, the GUID of a driver and the GUID of a displayed attribute are the same.
You frequently need a container for different presentation drivers. The class TPrsStd_DriverTable provides this service. You can add a driver to the table, see if one is successfully added, and fill it with standard drivers.
To fill a driver table with standard drivers, first initialize the AIS viewer as in the example above, and then pass the return value of the method InitStandardDrivers to the driver table returned by the method Get. Then attach a TNaming_NamedShape to a label and set the named shape in the presentation attribute using the method Set. Then attach the presentation attribute to the named shape attribute, and the AIS_InteractiveObject, which the presentation attribute contains, will initialize its drivers for the named shape. This can be seen in the example below.
Example
Function services aggregate data necessary for regeneration of a model. The function mechanism - available in the package TFunction - provides links between functions and any execution algorithms, which take their arguments from the data framework, and write their results inside the same framework.
When you edit any application model, you have to regenerate the model by propagating the modifications. Each propagation step calls various algorithms. To make these algorithms independent of your application model, you need to use function services.
Take, for example, the case of a modeling sequence made up of a box with the application of a fillet on one of its edges. If you change the height of the box, the fillet will need to be regenerated as well.
The class TFunction_Function is an attribute, which stores a link to a function driver in the data framework. In the static table TFunction_DriverTable correspondence links between function attributes and drivers are stored.
You can write your function attribute, a driver for such attribute (which updates the function result in accordance to a given map of changed labels), and set your driver with the GUID to the driver table.
Then the solver algorithm of a data model can find the Function attribute on a corresponding label and call the Execute driver method to update the result of the function.
For updating algorithm optimization, each function driver has access to the TFunction_Logbook object that is a container for a set of touched, impacted and valid labels. Using this object a driver gets to know which arguments of the function were modified.
An application must implement its functions, function drivers and the common solver for parametric model creation. For example, check the following model (see the following illustration):
The procedure of its creation is as follows:
Writing and reading XML files in OCCT is provided by LDOM package, which constitutes an integral part of XML OCAF persistence, which is the optional component provided on top of Open CASCADE Technology.
The Light DOM (LDOM) package contains classes maintaining a data structure whose main principles conform to W3C DOM Level 1 Recommendations. The purpose of these classes as required by XML OCAF persistence schema is to:
This package covers the functionality provided by numerous products known as "DOM parsers". Unlike most of them, LDOM was specifically developed to meet the following requirements:
Both these requirements are important when XML files are processed by applications if these files are relatively large (occupying megabytes and even hundreds of megabytes). To meet the requirements, some limitations were imposed on the DOM Level 1 specification; these limitations are insignificant in applications like OCAF. Some of these limitations can be overridden in the course of future developments. The main limitations are:
LDOM is dependent on Kernel OCCT classes only. Therefore, it can be used outside OCAF persistence in various algorithms where DOM/XML support may be required.
The drivers for document storage and retrieval manage conversion between a transient OCAF Document in memory and its persistent reflection in a container (disk, memory, network ...). For XML Persistence, they are defined in the package XmlDrivers.
The main methods (entry points) of these drivers are:
The most common case (which is implemented in XML Persistence) is writing/reading document to/from a regular OS file. Such conversion is performed in two steps:
First it is necessary to convert the transient document into another form (called persistent), suitable for writing into a file, and vice versa. In XML Persistence LDOM_Document is used as the persistent form of an OCAF Document and the DOM_Nodes are the persistent objects. An OCAF Document is a tree of labels with attributes. Its transformation into a persistent form can be functionally divided into two parts:
The driver for each attribute is selected from a table of drivers, either by attribute type (on storage) or by the name of the corresponding DOM_Element (on retrieval). The table of drivers is created by by methods XmlDrivers_DocumentStorageDriver::AttributeDrivers() and XmlDrivers_DocumentRetrievalDriver::AttributeDrivers().
Then the persistent document is written into a file (or read from a file). In standard persistence Storage and FSD packages contain classes for writing/reading the persistent document into a file. In XML persistence LDOMParser and LDOM_XmlWriter are used instead.
Usually, the library containing document storage and retrieval drivers is loaded at run time by a plugin mechanism. To support this in XML Persistence, there is a plugin XmlPlugin and a Factory() method in the XmlDrivers package. This method compares passed GUIDs with known GUIDs and returns the corresponding driver or generates an exception if the GUID is unknown.
The application defines which GUID is needed for document storage or retrieval and in which library it should be found. This depends on document format and application resources. Resources for XML Persistence and also for standard persistence are found in the StdResource unit. They are written for the XmlOcaf document format.
There is one attribute driver for XML persistence for each transient attribute from a set of standard OCAF attributes, with the exception of attribute types, which are never stored (pure transient). Standard OCAF attributes are collected in six packages, and their drivers also follow this distribution. Driver for attribute T*_* is called XmlM*_*. Conversion between transient and persistent form of attribute is performed by two methods Paste() of attribute driver.
XmlMDF_ADriver is the root class for all attribute drivers.
At the beginning of storage/retrieval process, one instance of each attribute driver is created and appended to driver table implemented as XmlMDF_ADriverTable. During OCAF Data storage, attribute drivers are retrieved from the driver table by the type of attribute. In the retrieval step, a data map is created linking names of DOM_Elements and attribute drivers, and then attribute drivers are sought in this map by DOM_Element qualified tag names.
Every transient attribute is saved as a DOM_Element (root element of OCAF attribute) with attributes and possibly sub-nodes. The name of the root element can be defined in the attribute driver as a string passed to the base class constructor. The default is the attribute type name. Similarly, namespace prefixes for each attribute can be set. There is no default value, but it is possible to pass NULL or an empty string to store attributes without namespace prefixes.
The basic class XmlMDF_ADriver supports errors reporting via the method WriteMessage(const TCollection_ExtendedString&). It sends a message string to its message driver which is initialized in the constructor with a Handle(CDM_MessageDriver) passed from the application by Document Storage/Retrieval Driver.
Every XML Document has one root element, which may have attributes and contain other nodes. In OCAF XML Documents the root element is named "document" and has attribute "format" with the name of the OCAF Schema used to generate the file. The standard XML format is "XmlOcaf". The following elements are sub-elements of <document> and should be unique entries as its sub-elements, in a specific order. The order is:
In XML documents, OCAF attributes are elements whose name identifies the OCAF attribute type. These elements may have a simple (string or number) or complex (sub-elements) structure, depending on the architecture of OCAF attribute. Every XML type for OCAF attribute possesses a unique positive integer "id" XML attribute identifying the OCAF attribute throughout the document. To ensure "id" uniqueness, the attribute name "id" is reserved and is only used to indicate and identify elements which may be referenced from other parts of the OCAF XML document. For every standard OCAF attribute, its XML name matches the name of a C++ class in Transient data model. Generally, the XML name of OCAF attribute can be specified in the corresponding attribute driver. XML types for OCAF attributes are declared with XML W3C Schema in a few XSD files where OCAF attributes are grouped by the package where they are defined.
The following example is a sample text from an XML file obtained by storing an OCAF document with two labels (0: and 0:2) and two attributes - TDataStd_Name (on label 0:) and TNaming_NamedShape (on label 0:2). The <shapes> section contents are replaced by an ellipsis.
The XML Schema defines the class of a document.
The full structure of OCAF XML documents is described as a set of XML W3C Schema files with definitions of all XML element types. The definitions provided cannot be overridden. If any application defines new persistence schemas, it can use all the definitions from the present XSD files but if it creates new or redefines existing types, the definition must be done under other namespace(s).
There are other ways to declare XML data, different from W3C Schema, and it should be possible to use them to the extent of their capabilities of expressing the particular structure and constraints of our XML data model. However, it must be noted that the W3C Schema is the primary format for declarations and as such, it is the format supported for future improvements of Open CASCADE Technology, including the development of specific applications using OCAF XML persistence.
The Schema files (XSD) are intended for two purposes:
The Schema definitions are not used by OCAF XML Persistence algorithms when saving and restoring XML documents. There are internal checks to ensure validity when processing every type of data.
Both the XML format and the XML OCAF persistence code are extensible in the sense that every new development can reuse everything that has been created in previous projects. For the XML format, this extensibility is supported by assigning names of XML objects (elements) to different XML Namespaces. Hence, XML elements defined in different projects (in different persistence libraries) can easily be combined into the same XML documents. An example is the XCAF XML persistence built as an extension to the Standard OCAF XML persistence [File XmlXcaf.xsd]. For the correct management of Namespaces it is necessary to:
In C++, the application behavior is implemented in virtual functions redefined in these derived classes. This is known as overriding.
There are four sample files provided in the directory 'OpenCasCade/ros/samples/ocafsamples'. They present typical actions with OCAF services (mainly for newcomers). The method Sample() of each file is not dedicated for execution 'as is', it is rather a set of logical actions using some OCAF services.
This sample contains templates for typical actions with the following standard OCAF attributes:
This sample contains template for the following typical actions:
This sample contains template for the following typical actions:
This sample contains template for typical actions with OCAF Topological Naming services. The following scenario is used: