In MeshViz Interface, the data structure used to store the mesh representation is not defined by the MeshViz Interface API as it is in most classical APIs such as 3DdataMaster.
For instance, in 3DdataMaster, a mesh can be created like in the following sample code:
Where the data and the geometry defining the mesh are copied into intermediate data structures which have a predefined type and organization.
With MeshViz Interface, the mesh passed to the extraction or data mapping classes is a reference to an object in the application which implements one of the MeshViz Interface mesh abstract interfaces.
A MeshViz Interface mesh contains a topology interface derived from MiTopology and a geometry interface derived from MiGeometry.
MiTopology derived classes return the Nth cell of the mesh as a class derived from the MiCell interface :
Similarly, MiGeometry derived classes return the Nth node (3D or 2D point) of the mesh.
MiCell derived classes must implement several methods to get the cell information, number of nodes, node indices, etc.
Scalar and vector sets are abstract interfaces of type MiDataSet which return the Nth value of the set as a double or a vector.
So instead of allocating and filling a set of arrays with the values read from the internal data structure like in legacy APIs, the application has to implement these abstract interfaces in its existing classes as in the following code snippet:
Class declaration (partial):
The Cell class implements the MiVolumeCell interface. In this example, they are all tetrahedrons so the number of facets is always 4, number of points is 4 and number of edges is 6. The other implementation methods are not shown here:
Usage of the extraction class:
In this code, the mesh is implemented in the TetraMeshBuilder class. It is a set of tetrahedron splitting a cube created for the purpose of the example. It is derived from a MiVolumeMeshUnstructured which represents a generic unstructured mesh. The mesh is passed to the MiSkinExtractUnstructured::getNewInstance() method which returns an abstract interface to a MiSkinExtractUnstructured object. Calling extractSkin() on this interface returns a MiSurfaceMeshUnstructured abstract interface which can be parsed to get the extracted polygons.
So, from a volume mesh implementing an abstract interface, the extraction mechanism produces an interface to a surface mesh.
The main advantages of this architecture are:
A mesh is a logical representation of a volume, a surface, or a line containing computed or measured values representing any type of data sets to be analyzed. A mesh is made up of cells having various shapes defined by their node points. The cells define the topology of the mesh whereas the node points define the geometry of the mesh. For instance a surface mesh can be made up of a set of triangles each having three nodes represented by 3D points. Data sets attached to the mesh can be given one for each cell or one for each node point. Each mesh has a dimension and an organization. The dimension is the dimension of its cells (1D, 2D or 3D) and the organization is the type of topology describing the mesh: structured where each cell knows its neighbors or unstructured where cells are defined independently from each other.
More precisely, the dimensions of a mesh are:
The mesh organizations available are:
The topology of this mesh is defined implicitly. Thus there is no need to implement a cell interface for this kind of mesh. Optimized algorithms do not need them. The topology of structured meshes is defined by MiTopologyIjk or MiTopologyIj which define only the number of cells in each dimension. Several derived classes are available depending on the type of geometry: Regular, Rectilinear or Curvilinear. Structured surface meshes inherit from MiMeshIj. Structured volume meshes inherit from MiMeshIjk. Meshes having an implicit geometry given by a bounding box inherit from MiMeshRegular. Traversing such a mesh can be much faster than traversing an unstructured mesh giving much better performance for some algorithms. See below for a detailed description of this type of geometry.
Some of the available interfaces do not contain any additional methods compared to their parent class (for instance MiMesh). They are provided for convenience to classify the different types of geometry/topology pairs representing a type of mesh.
There are three main types of structured meshes. They all share the same topology defined by the MiTopologyIjk interface representing a 2D or 3D matrix of quadrangles or hexahedron cells. However, they differ in their geometry.
As described above, structured meshes contain only hexahedron cells and thus do not require implementing any specific cell interface. All extraction algorithms are able to figure out the exact description of each cell by looking at the point list. This is not the same for unstructured meshes where cells can have any kind of shape. In this case, the interface derived from MiTopologyI contains a list of line (MiLineCell), surface (MiSurfaceCell) or volume (MiVolumeCell) cells.
They are the most complex interfaces to implement since they must be able to return advanced topological information required by extraction algorithms. Even though some of the MiCell methods are simple descriptions of the cell’s topology (number of edges, list of facets and list of points) and are thus easy to implement, some other methods are more complex and require further explanation. Some extraction algorithms, such as isosurface computation, stream lines and point probing, need to know specific information about the cell that depends on the cell’s shape.
For volume cells, these methods are:
Obviously, the internal extraction algorithms depend on the implementation of such methods. So a set of utility classes are provided for the most common shapes: tetrahedron, wedge, pyramid and hexahedron providing a static implementation of these methods. For instance, the MxHexahedronCellExtract class contains the implementation of these methods for an hexahedron. So when implementing an hexahedron cell in your own cell code, you can just call the MxHexahedronCellExtract::getIsosurfTopology in the getIsosurfTopology method of your cell implementation.
If you don’t do that, your application may work as long as you don’t use one of the extraction algorithms that requires them such as isosurface, stream lines or point probe. These methods are not pure virtual and their default implementation (from MiCell) throws an exception to show you that the extraction method used requires a valid implementation.
For other shapes, such as a generic polyhedron, an implementation may not be possible. Thus, these cells must be converted to a set of basic cells before calling the extract algorithm. See Support of polygonal surface meshes and polyhedral volume meshes for more details on converting a polyhedral mesh.
Notice also that when using these utility classes, the cells must follow some strict orientation rules relative to the parametric coordinate space. See the documentation of these classes for a detailed description of the required topologies.
See the MeshViz Implementation library for valid examples on how to implement a generic cell.
Data sets are values attached to a cell or to point nodes that must be analyzed. In some fields of application, they are also called fields, properties or attributes. They can be scalar or vector sets.
Any number of data sets can be analyzed for each mesh using any type of internal representation (float, double, char, bytes,…) or even implicit data computed on the fly. This is possible thanks to the MiDataSet interface. This template interface is a very powerful solution for defining data sets associated with a mesh. The template definition is used to define the dimension of the associated data: Scalar sets are one-dimension data, vector sets are tri-dimension data.
Data sets are not stored in the mesh. This is because a data set is associated with a mesh only during a feature extraction operation. Thus, several extracts can be done on the same mesh for different data sets.
Data can be given per cell or per node as specified by the getBinding() method. When the binding is defined per cell, the index of the data set matches the index of the cells. When the binding is defined per node, the index of the data set matches the index of the nodes.
Data sets type and organization must be consistent with the mesh type they are used with. Unstructured meshes support MiDataSetI data sets. Structured meshes support MiDataSetIj and MiDataSetIjk data sets. For unstructured IJK meshes, when the binding is per node, data are unstructured (derived from MiDataSetI) but when the binding is per cell, since the cells are structured, data sets derive from MiDataSetIjk.
Several specialized types are provided for convenience such as MiScalardSetI that can store any scalar field for temperature, pressure, etc and MiVec3dSetI for storing 3D vector fields.
Similar to geometry interfaces, a MiDataSet interface completely hides the storage type used by the application. This is done by returning double for scalar fields and MbVec3d for vector fields. This cast operation allows you to store internally data sets as shorts, bytes, double or floats or to compute them on the fly.
Most interfaces have a getTimeStamp() method. This method can be used to notify the MeshViz extractors that the content of the object implementing the interface has changed. Thus, MeshViz extractors are informed that they must be recomputed. Any value can be used to represent the time stamp (not only time). A simple integer value incremented each time the values are changed is mandatory. Furthermore, this integer must be unique across objects implementing the same interface. This allows the MeshViz extractors to identify these objects. Using the utility class MxTimeStamp ensures an application to respect this rules. Note that this static class is not thread safe.
Often a mesh contains cells having undefined values. You may also want to limit your study to a specific set of cells given by their index range or by their position in space. Two mechanisms are provided for doing that: Cell Filters and Dead Cells.
A Cell Filter is an user class implementing the MiCellFilter interface passed to the Mesh Extraction objects. It contains a method called for each cell returning true for accepted cells and false for rejected cells.
Like for cells, the Cell Filter can have a structured or an unstructured interface. Structured interfaces derives from MiCellFilterIj or MiCellFilterIjk. They contain a method acceptCell(i,j,k) indexed exactly like cells. Similarly, for an unstructured mesh, the MiCellFilterI::acceptCell method of the class MiCellFilterI has only one parameter representing the cell index.
The following source code shows a simple filter accepting cells indexed in the range 101 to 199 for an unstructured mesh.
Obviously, since you have access to your own internal data structure, you may get the real cell and do more complex filtering operations. Cell filtering is well adapted to dynamic filters that can change on the fly. For instance, when one wants to temporary isolate a group of cells to have a simplified view of part of a mesh.
When the filtering is static, that is when some cells are always undefined, use the dead cell mechanism. The mesh topology interface contains two methods for managing dead cells that must be implemented in the application:
This is not a pure virtual method because, since most meshes will not use dead cells, it defaults to false to avoid to have to reimplement it..