This chapter describes how to provide access to chemical system data. The Molecular Inventor software distribution includes the ChemData class, which is derived from the base data class, ChemBaseData. You can use an instance of ChemData directly in your application or you can use it as a model for deriving your own data node.
This chapter contains the following sections:
“Deriving a Data Node” describes how to derive a class from ChemBaseData.
“Exploring ChemData.h” describes the header file for the ChemBaseData-derived class ChemData.
“Exploring ChemData.c++” describes the source code for the ChemBaseData-derived class ChemData.
“The Entire ChemData.c++ Source” contains a listing of the ChemData.c++ source code.
If you are deriving your own data node, you should read, The Inventor Toolmaker, which is included with the Open Inventor Development Kit.
![]() | Note: In this guide, the term “data node” refers to any ChemBaseData-derived class, such as ChemData. |
ChemBaseData is a base Molecular Inventor (MI) class from which you must derive your own data class. MI uses the derived data class to access the chemical system data.
MI requires that the derived class contain, at a minimum, the following information:
the number of atoms
the number of bonds
a series of get functions, supplied by the developer, that allow MI to access the chemical system data
a constructor
Because MI uses get...() methods supplied by the ChemBaseData-derived class to access chemical system data, MI makes no requirements on the data structures that store your chemical system data. The ChemData class provided with MI, for example, stores chemical system data in Open Inventor fields.
The fields maintained by the data node are the number of atoms and bonds in the chemical system data, and any associated data.
SoSFInt32 numberOfAtoms; SoSFInt32 numberOfBonds; SoSFNode associatedData; |
The optional field, associatedData, contains an instance of the ChemAssociatedData class. This class holds ASCII or binary information that is descriptive of the chemical system but which is not required by MI for rendering. Often the associatedData field is used as a mechanism for transferring additional information about a chemical system between applications.
For more information about ChemAssociatedData, see “Maintaining Additional Information About a Chemical System.”
When you derive your own data class from ChemBaseData, you must implement the following methods that provide access to chemical system data:
virtual short getAtomicNumber(int32_t index) const; virtual int32_t getAtomId(int32_t index) const; virtual const SbString & getAtomName(int32_t index) const; virtual int32_t getAtomIndex(int32_t index) const; virtual const SbVec3f & getAtomCoordinates(int32_t index) const; virtual int32_t getBondFrom(int32_t index) const; virtual int32_t getBondTo(int32_t index) const; virtual int getBondType(int32_t index) const; virtual int32_t getBondIndex(int32_t index) const; |
The following table defines these methods.
Table 3-1. ChemDisplay Methods
Method | Description |
|---|---|
returns the atomic number of the atom with the specified index. The value returned is used for labeling atoms and for optionally turning off the display of hydrogens. | |
returns the ID of the atom with the specified index; the ID is a numeric identifier. The value returned is used for labeling atoms. | |
returns the name of the atom with the specified index. The value returned is used for labeling atoms. | |
returns the entry to use with the ChemColor and ChemRadii tables for the atom with the specified index if ATOM_PER_ATOM_INDEXED is used as the value for the atomRadiiBinding or atomColorBinding fields in ChemRadii or ChemColor, respectively. | |
returns the coordinates of the atom with the specified index. | |
returns the entry for the “from” atom in the bond with the specified bond index. Each bond is composed of a “from” and “to” atom. The returned value is used as the argument for the getAtom*() methods. | |
returns the entry for the “to” atom in the bond with the specified bond index. The returned value is used as the argument for the getAtom*() methods. | |
returns the type of bond with the given index; it must be one of the enum values of BondType in ChemBaseData, such as, SINGLE_BOND, DOUBLE_BOND, or TRIPLE_BOND. | |
returns the entry to use with the ChemColor bondColor table if BOND_PER_BOND_INDEXED is used as the value of bondColorBinding in the ChemColor node |
All of these methods use an index number as an argument. If you think of the data accessed by the get...() methods as being stored in arrays, the index is the particular element in the array. For example, if atomicNumber contained the values listed below, chemData->getAtomicNumber(2) would return the value 8, which is the value of the third (numbering starts at 0) element the atomic number array.
atomicNumber [ 7, 6, 8, 7, 6, 8, 6, 6,
6, 6, 6, 6, 7, 7, 7, 1,
6, 6, 8, 1, 8, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1 ]
|
Once a scene graph is created, actions are applied to the scene graph to cause something to happen. Examples of actions include SoGLRenderAction, that causes the scene graph to be rendered, SoWriteAction, that causes the scene graph to be written to a file, and SoGetBoundingBoxAction, that computes a 3D bounding box for all of the objects in the scene graph. Actions are applied to each node in the scene graph by invoking methods within a node. These methods are either inherited from the base Open Inventor classes or they are supplied by a specific class.
Actions invoked on a grouping node spread to its children nodes in a defined order. For more information about how actions are carried out in a scene graph, see Chapter 3 of The Inventor Mentor.
ChemBaseData-derived nodes must handle the following primary actions: SoGLRenderAction, SoCallbackAction, SoGetBoundingBoxAction and SoPickAction. It is the ChemDisplay node that renders or generates information in response to these actions. ChemDisplay, however, needs the information contained in the data node, the ChemDisplayParam node, the ChemRadii node, and the ChemColor node to handle these actions. Consequently, all of the nodes must respond appropriately to these actions by making their information available to the ChemDisplay node.
A ChemBaseData-derived node makes its information available by placing a pointer to itself in the traversal state. This functionality is provided by the ChemBaseDataElement class. Therefore, in response to the actions described above, a data node just needs to invoke the set() method of the ChemBaseDataElement class. The ChemData class provides an example of this implementation.
![]() | Note: If your ChemBaseData-derived class does not store its data in Open Inventor field types, you must implement methods that handle the writing of data, in response to a SoWriteAction, and the reading of data from an Inventor file. |
For more information regarding actions, refer to Chapter 9 of The Inventor Mentor. For more information about creating nodes, refer to The Inventor Toolmaker.
Sometimes you might like to maintain more information about a chemical system than is required by MI for rendering. To maintain this non-rendering information, you can either create your own ChemBaseData-derived node which contains fields to hold this information, or you can use the associatedData field which is defined in the ChemBaseData class.
To make use of this field, your application must create an instance of ChemAssociatedData and then set the value of the associatedData field in a data node to the instance of ChemAssociatedData, for example:
ChemData *chemData = new ChemData; ChemAssociatedData *cad = new ChemAssociatedData; ... chemData->associatedData.setValue((SoNode *)cad); |
In this example, cad is a pointer to a newly-created instance of ChemAssociatedData. The last line of code sets the value of chemData's associatedData field to the instance of ChemAssociatedData.
![]() | Note: The setValue() method increments the reference count on cad so that it is not deallocated by Open Inventor. |
If the associatedData field contains data, that data is written to an Inventor file when an SoWriteAction is applied to the data node. The field thereby provides a mechanism to easily transfer data between applications. If you do not use the associatedData field but store the additional information within Open Inventor fields, the information is also written to an Inventor file upon invocation of a SoWriteAction. If you do not use the associatedData field and do not use Open Inventor fields to store the additional information, you must provide a write() method for your data node. For more information, see The Inventor Toolmaker.
![]() | Note: The remainder of this chapter explores the ChemData class. Use its explanation as a guide for creating your own ChemBaseData-derived data node. |
The software distribution includes ChemData, which is a class derived from ChemBaseData. You can use ChemData directly in your application or you can use it as a model for deriving your own data node.
This section describes the header file for the ChemData class found in /usr/include/ChemKit/ChemData.h.
ChemData.h includes the ChemBaseData.h and ChemDefs.h header files. ChemDefs.h contains definitions which allow MI to be compatible with versions 2.0 and 2.1 of Open Inventor.
#include <ChemKit/ChemDefs.h> #include <ChemKit/ChemBaseData.h> |
The remaining header files include declarations of the Open Inventor fields used by ChemData and the declaration of SoSubNode from which all Open Inventor nodes are derived.
#ifdef IV2_0 #include <Inventor/fields/SoSFLong.h> #include <Inventor/fields/SoMFLong.h> #else #include <Inventor/fields/SoSFInt32.h> #include <Inventor/fields/SoMFInt32.h> #endif #include <Inventor/fields/SoMFEnum.h> #include <Inventor/fields/SoMFShort.h> #include <Inventor/fields/SoMFString.h> #include <Inventor/fields/SoMFVec3f.h> #include <Inventor/nodes/SoSubNode.h> |
ChemData.h uses the following lines to create a class named ChemData which is derived from ChemBaseData:
class ChemData : public ChemBaseData {
SO_NODE_HEADER(ChemData);
|
The following lines declare the fields used in ChemData:
public:
// Fields - Atoms
SoMFShort atomicNumber;
SoMFInt32 atomId;
SoMFString atomName;
SoMFInt32 atomIndex;
SoMFVec3f atomCoordinates;
// Fields - Bonds
SoMFInt32 bondFrom;
SoMFInt32 bondTo;
SoMFEnum bondType;
SoMFInt32 bondIndex;
|
The following table describes the contents of these fields.
ChemData Fields | Description |
|---|---|
is the atomic number of an atom. ChemDisplay renders the atomic numbers of atoms if this is specified in ChemDisplayParam. | |
is the unique, numeric ID for each atom in the chemical system. ChemDisplay renders the IDs of the atoms if this is specified in ChemDisplayParam. | |
is the name of each atom in the chemical system. ChemDisplay renders the names of the atoms if this is specified in ChemDisplayParam. | |
contains lookup information to find the color and radii of an atom in tables defined in the ChemColor and ChemRadii nodes. | |
are the coordinates for each atom in a chemical system. | |
is used as an index into the atom SoMFFields in order to access information about the “from” atom. Each bond is composed of a “from” and “to” atom. | |
is used as an index into the atom SoMFFields in order to access information about the “to” atom. Each bond is composed of a “from” and “to” atom. | |
is the type of bond; it must be one of the enum values of BondType in ChemBaseData, such as, SINGLE_BOND, DOUBLE_BOND, or TRIPLE_BOND. | |
contains lookup information to find the color of a bond in the bond-color table defined in the ChemColor node. |
ChemData.h provides declarations and implementations of all of the get...() methods in ChemBaseData, as described in “The Get Methods.” In addition, ChemData defines the following methods.
Method | Description |
|---|---|
ChemData() | is the class constructor; it creates an instance of ChemData with default settings. |
~ChemData() | is the class destructor which is empty. |
empties all of the SoMFFields so the node can be used for a different chemical system. | |
is invoked when a SoCallbackAction is applied to the node. It in turn invokes the doAction() method. | |
is invoked when a SoGLRenderAction is applied to the node. It in turn invokes the doAction() method. | |
is invoked when a SoPickAction is applied to the node. It in turn invokes the doAction() method. | |
is invoked when a SoGetBoundingBoxAction is applied to the node. It in turn invokes the doAction() method. | |
invokes the ChemBaseDataElement->set() method that places a pointer to the node in the traversal state |
The implementation of a data node depends on the data structures used for storing chemical system data. There are, however, parts of ChemData.c++ that any derived class must implement. The following sections describe those parts.
Every data node must include the header files for the classes it uses. Your data node might include header files similar to ChemData.c++. The ChemData.h header file contains the declarations of the ChemData class.
#include <ChemKit/ChemData.h> |
When actions are applied to the data node, the set() method of the ChemBaseDataElement class is ultimately invoked. Therefore, the header file for ChemBaseDataElement must be included as must the header files for the actions handled by the data node.
#include <ChemKit/ChemBaseDataElement.h> #include <Inventor/actions/SoGLRenderAction.h> #include <Inventor/actions/SoCallbackAction.h> #include <Inventor/actions/SoGetBoundingBoxAction.h> #include <Inventor/actions/SoPickAction.h> |
Every data node must declare itself as a node, provide a constructor and a destructor, and, if Open Inventor fields are used to hold the chemical system data, declare and provide default values for each of its fields. The constructor for the ChemData class is shown in the following section of ChemData.c++:
SO_NODE_SOURCE(ChemData);
ChemData::ChemData()
{
SO_NODE_HEADER(ChemData);
SO_NODE_CONSTRUCTOR(ChemData);
SO_NODE_ADD_FIELD(atomicNumber, (0));
SO_NODE_ADD_FIELD(atomId, (0));
SO_NODE_ADD_FIELD(atomName, (””));
SO_NODE_ADD_FIELD(atomIndex, (0));
SO_NODE_ADD_FIELD(atomCoordinates, (0.0, 0.0, 0.0));
SO_NODE_ADD_FIELD(bondFrom, (0));
SO_NODE_ADD_FIELD(bondTo, (0));
SO_NODE_ADD_FIELD(bondType, (0));
SO_NODE_ADD_FIELD(bondIndex, (0));
SO_NODE_SET_MF_ENUM_TYPE(bondType, BondType);
}
|
For more information about creating nodes and fields within Open Inventor, see The Inventor Toolmaker.
The ChemData header file declares and implements the get...() methods for the ChemData class. The implementations of these methods vary according to the manner in which data is accessed for your ChemBaseData-derived node.
The following methods in your class are invoked when actions, described in “The Action Methods,” are applied to a scene graph containing your node:
virtual void callback(SoCallbackAction *action); virtual void GLRender(SoGLRenderAction *action); virtual void pick(SoPickAction *action); virtual void getBoundingBox(SoGetBoundingBoxAction *action); |
In ChemData, all of these methods invoke the doAction() method which in turn invokes the set() method of ChemBaseDataElement. You can very likely use the following code from ChemData.c++ directly in your ChemBaseData-derived class after changing ChemData:: to the name of your class.
void
ChemData::doAction(SoAction *action)
{
ChemBaseDataElement::set(action->getState(), this, this);
}
void
ChemData::GLRender(SoGLRenderAction *action)
{
ChemData::doAction(action);
}
void
ChemData::pick(SoPickAction *action)
{
ChemData::doAction(action);
}
void
ChemData::callback(SoCallbackAction *action)
{
ChemData::doAction(action);
}
void
ChemData::getBoundingBox(SoGetBoundingBoxAction *action)
{
ChemData::doAction(action);
}
|
Since the source file for the ChemData class is not included in the distribution, it is listed here in its entirety.
#include <ChemKit/ChemData.h>
#include <ChemKit/ChemBaseDataElement.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoCallbackAction.h>
#include <Inventor/actions/SoGetBoundingBoxAction.h>
#include <Inventor/actions/SoPickAction.h>
SO_NODE_SOURCE(ChemData);
ChemData::ChemData()
{
SO_NODE_CONSTRUCTOR(ChemData);
SO_NODE_ADD_FIELD(atomicNumber, (0));
SO_NODE_ADD_FIELD(atomId, (0));
SO_NODE_ADD_FIELD(atomName, (““));
SO_NODE_ADD_FIELD(atomIndex, (0));
SO_NODE_ADD_FIELD(atomCoordinates, (0.0, 0.0, 0.0));
SO_NODE_ADD_FIELD(bondFrom, (0));
SO_NODE_ADD_FIELD(bondTo, (0));
SO_NODE_ADD_FIELD(bondType, (0));
SO_NODE_ADD_FIELD(bondIndex, (0));
SO_NODE_SET_MF_ENUM_TYPE(bondType, BondType);
isBuiltIn = TRUE;
}
ChemData::~ChemData()
{
}
void
ChemData::doAction(SoAction *action)
{
ChemBaseDataElement::set(action->getState(), this, this);
}
void
ChemData::GLRender(SoGLRenderAction *action)
{
ChemData::doAction(action);
}
void
ChemData::pick(SoPickAction *action)
{
ChemData::doAction(action);
}
void
ChemData::callback(SoCallbackAction *action)
{
ChemData::doAction(action);
}
void
ChemData::getBoundingBox(SoGetBoundingBoxAction *action)
{
ChemData::doAction(action);
}
void
ChemData::reset()
{
atomicNumber.deleteValues(0,-1);
atomId.deleteValues(0,-1);
atomName.deleteValues(0,-1);
atomIndex.deleteValues(0,-1);
atomCoordinates.deleteValues(0,-1);
bondFrom.deleteValues(0,-1);
bondTo.deleteValues(0,-1);
bondType.deleteValues(0,-1);
bondIndex.deleteValues(0,-1);
}
|