Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
DdataMaster

Introduction

3DdataMaster defines extension nodes to Open Inventor primarily for the development of scientific visualizations. Before going any further it is very important to have read What You Must Know about MeshViz XLM:.

Important note:

  • The C++ implementation of 3DdataMaster is kept for compatibility with older versions. You should use MeshViz Interface instead of 3DdataMaster.
  • For Java and .NET developers, since implementing C++ interfaces in other languages is not possible without writing heavy cross language bridges, we recommand to continue to use 3DdataMaster.

Introduction to Meshes

Mesh definition

All mesh types are derived from the PbMesh basic type. A mesh definition is basically given by a set of value sets. The following methods are used to initialize the meshes. The addValuesSet() method allows you to add a set of values to your mesh; removeValuesSet() or removeAllValuesSet() allows you to remove one or all of the sets. The getNumValuesSet() method returns the number of value sets associated with a mesh; getMinValuesSet() and getMaxValuesSet() return the minimum and the maximum values for a given set. For example, a value set may be the list of temperatures for each node of your mesh, or a list of pressures for each cell of your mesh. The setGeometry() method is defined for each of the basic types and allows you to initialize the node coordinates of your mesh. Please refer to PbMesh and its derived classes for a full description of these methods.

Mesh visualization

To visualize data from a mesh, you must instantiate a class derived from PoMesh , depending on the type of visualization you need. For example PoMeshSkin allows you to visualize the skin of a volume mesh. These classes are derived from Open Inventor node kits and we call them “visualization node kits.”

Link between mesh definition and mesh visualization

As a visualization node kit depends, of course, on the data describing the mesh, you must also define a relationship between the PoMesh instance and the PbMesh instance. MeshViz provides two ways to specify this relation:

, which is an Open Inventor node containing an Open Inventor field derived from PoSFMesh , itself containing an instance derived from PbMesh . Then you must add this property mesh node to the scene graph so that it will be inherited during traversal and used by the different visualization node kits you define. The methods setGeometry() and addValuesSet() are also available in the subclasses of PoMeshProperty class and build for you the instance of the contained PbMesh object.

See also the the section called “Property and Visualization Classes”.

+ As a mesh object can contain several data sets, the visualization
 node kit can select one by using **PoMesh::valuesIndex** to color the shape in the node kit. For a 2D mesh
 representation, you can also use **PoMesh2D::zValuesIndex** to specify an elevation at each mesh node.

Mesh coloring

The PoMesh::coloringType field of the visualization node allows you to select the type of coloring that will be applied if necessary (refer to the following the section called “Surface Meshes”, for the explanation of these coloring methods). If data mapping coloringType is not COLOR_INHERITED, a data mapping object must be created to specify the data-to-color mapping, and if coloringType equals COLOR_CONTOURING or COLOR_TEXTURE_CONTOURING, an isovalueList object must be created to specify the list of isovalues. A data mapping object is defined by an instance of either the class PbDataMapping or the class PoDataMapping. An isovalueList object is defined by an instance either of the class PbIsovaluesList or the class PoIsovaluesList. (Refer to the section called “Data-to-Color Mapping” and the section called “Defining Isovalues”).

When coloring a value set that has its values located at a cell (see the section called “Location of values”), the cells are always colored with a unique color even when the color type
(coloringType field) is COLOR_AVERAGE, COLOR_MAPPING,
COLOR_CONTOURING, or COLOR_TEXTURE_CONTOURING.

A first example

The following code fragments define the objects necessary to visualize the skin and a cross-section of a volume mesh. This example uses the Pb[xxx]objects and the PoMesh::set[xxx](Pb[xxx] *pb) methods.

Example : Visualize a skin and a cross-section of a volume mesh

PbCartesianGrid3D pb_mesh;
pb_mesh.setGeometry( ... );
pb_mesh.addValuesSet( data_index, dataset );
PbLinearDataMapping pb_datamapping;
PoMeshSkin* skin = new PoMeshSkin;
skin->coloringType = PoMesh::COLOR_MAPPING;
skin->valuesIndex( data_index );
skin->setMesh( &pb_mesh );
skin->setDataMapping( &pb_datamapping );
PoMeshCrossSection* cross_section = PoMeshCrossSection;
cross_section->coloringType = PoMesh::COLOR_MAPPING;
cross_section->valuesIndex( data_index );
cross_section->setMesh( &pb_mesh );
cross_section->setDataMapping( &pb_datamapping );
SoGroup* group = new SoGroup;
group->addChild( skin );
group->addChild( cross_section );

Example : Uses the Po property nodes included in the scene graph

PoCartesianGrid3D* po_mesh = new PoCartesianGrid3D;
po_mesh->setGeometry( ... );
po_mesh.addValuesSet( data_index, dataset );
PoLinearDataMapping* po_datamapping = new PoLinearDataMapping;
PoMeshSkin* skin = new PoMeshSkin;
skin->coloringType = PoMesh::COLOR_MAPPING;
skin->valuesIndex( data_index );
PoMeshCrossSection* cross_section = PoMeshCrossSection;
cross_section->coloringType = PoMesh::COLOR_MAPPING;
cross_section->valuesIndex( data_index );
SoGroup* group = new SoGroup;
group->addChild( po_mesh );
group->addChild( po_datamapping );
group->addChild( skin );
group->addChild( cross_section );

Location of values

The values of a mesh can be located either at the cells of the mesh or at the nodes of the mesh.

Values at cells:

When the values are located at a cell, each cell is drawn with only one color. For instance when drawing a cross-section, the shape used to draw the intersection between the plane and a cell is colored with one color. When drawing the skin of a mesh, the face of a cell that “belongs” to the skin is also colored with one color. The color used depends on the value of this cell.

At this time, value sets with per-cell data can only be used by the
classes PoMeshLevelSurf, PoMeshSkin, and PoMeshCrossSection.

To define a value set with values located at the cells of the mesh, use the following method:

my_mesh->addValuesSet( set_index, cell_values, PER_CELL );
  • where my_mesh can be an instance of PbMesh or PoMeshProperty.
  • cell_values contains the same number of floats as the number of cells in the mesh.
  • cell_values[i] is the value of the i-th cell of the mesh.

Values at nodes:

When the values are located at the nodes of the mesh, each cell is drawn using the values of each node of the cell. How these nodes’ values are used to draw the cell depends on the coloring mode. (see the section called “Mesh coloring”).

To define a values set located at node, use the following method:

my_mesh->addValuesSet( set_index, cell_values, PER_NODE );
  • where my_mesh can be an instance of PbMesh or PoMeshProperty.
  • cell_values contains the same number of floats as the number of nodes in the mesh.
  • cell_values[i] is the value of the i-th node of the mesh.

Cell filter

Filtering cells is a way to specify which cells are used to build the mesh representation. A cell filter is based only on the method acceptCell() of the class PoCellFilter . When acceptCell() returns TRUE, the cell given as the argument is used for the representation, otherwise the cell is not taken into account by the representation.

A cell filter does not apply any transparency to a rejected cell. When a cell is not accepted, it is as if the mesh did not contain this cell. A transparency applied to a cell of mesh skin would create a hole in the surface, whereas the cell filter actually modifies the geometry of the skin.

In order to define a custom cell filter, you must create a class derived from PoCellFilter and implement the method acceptCell() per your needs. It has two arguments, the index of the cell, and the float value at this cell. This allows you to filter the cell based on its index or a property at this cell. For instance, a filter could eliminate all cells having a value greater than a specified value, or eliminate the last 100 cells of the mesh.

The value passed as the second argument to acceptCell() is an element of the scalar data set currently selected by the representation. This data set is selected by setting the field PoMesh::valuesIndexForCellFilter.

The class PoIntervalCellFilter is a predefined implementation of a cell filter. It implements the acceptCell() method by simply checking if the value of a cell is between a given min and max range.

Example : Visualize a skin using a cell filter based on the float value at the cell The filter rejects each cell whose value (here property_for_filter) is not between 100 and 200.

float property_for_color[NUM_NODES];
float property_for_filter[NUM_CELLS];
PoHexahedronMesh3D mesh;
mesh.setGeometry( ... );
mesh.addValuesSet( 0, property_for_color ); // gives a property that is used to
// compute the colors of the skin
mesh.addValuesSet( 1, property_for_filter, PbMesh::PER_CELL );
// gives a property for
// each cell, that will be used by the filter
PoMeshSkin* skin = new PoMeshSkin;
skin->coloringType = PoMesh::COLOR_MAPPING;
skin->valuesIndex( 0 );
skin->valuesIndexForCellFilter( 1 ); // select the property_for_filter as the data
// set used by the filter
PoIntervalCellFilter* filter = new PoIntervalCellFilter;
filter->min = 100;
filter->max = 200;
filter->in = TRUE;
root->addChild( mesh );
root->addChild( filter );
root->addChild( skin );

In this example, the skin building process calls acceptCell() like this:

For each index of cell (cell_index) {

if acceptCell (cell_index, property_for_filter[cell_index]) is true

then include this cell in the skin

}

If valuesIndexForCellFilter is -1 or if there is no data set corresponding to the specified index, acceptCell() is called with 0 as its second argument.

PoMeshSkin, PoMeshCrossSection, PoMeshLevelSurf,PoMeshCrossContour, PoMeshSkeleton, PoMeshProbePoint, PoBaseStreamLine (and derived classes), as well as PoMesh3DVecCrossSection, use the cell filter (PoCellFilter) inherited from the scene graph.

Surface Meshes

2D and 3D surface meshes types

3DdataMaster provides the following types to deal with your 2D and 3D surface meshes (the indentation shows class derivations):

Surface mesh representation node classes

To draw contour lines on your mesh with or without annotations. You can define main and sub lines. Only main lines will be annotated and you can then customize the annotation. For example, if you want them to be included in the contour line with or without a background, you can ask 3DdataMaster to clip the line around the bounding box of the annotation string, you can also force all the annotations to either be horizontal, or vertical or following the line slope, etc. The “contouring-values” (see the section called “Defining Isovalues”) are defined by the connected PbIsovaluesList object or the PoIsovaluesList object inherited during traversal.

To draw vectors field on a 2D Mesh. Figure 2.49. Surface mesh representation node classes

Volume Meshes

3D volume mesh types

3DdataMaster provides the following basic types to deal with your 3D volume meshes (indentation shows class derivation):

Volume mesh representation node classes

This class defines a cross-section of the 3D volume and then builds solid contouring visualization on this plane using the current data-color mapping method.

This class builds the intersection between a cross-section of the mesh and its skin. This contour intersection can be colored using the current data-color mapping method. This representation can be useful for visualizing the position of a cross-section. The following image shows a transparent skin and a cross-contour made of two contours.

This class draws a 3D skeleton of the 3D mesh by building a set of X, Y and Z plane cross contours. The following image shows a transparent skin and a skeleton made of two X-contours, two Y-contours, and two Z-contours.

This class builds a 3D isosurface. The color of this 3D surface is specified by the current color associated with the surface value. The following image shows a transparent skin and a colored level surface. In this example, two scalar data sets are used to build the level surface. The first one defines the geometry of the level surface and the other one the coloration. The coloration is done using the current “value-to-color mapping” (see the section called “Data-to-Color Mapping”).

This class builds a vector field on a volume mesh. Each vector of the vector data set is taken into account to build the representation. The set of vector data is selected by the field PoMesh::vecsIndex.

This class builds a vector field on a cross-section of a volume mesh. A vector is drawn at each of the edges intersecting the cross-section. The value and direction of a vector is computed by linear interpolation between the two nodes of the edge intersecting the cross-section. The set of vector data is selected by the field PoMesh::vecsIndex.

This class builds a vector field on a regular grid mapped onto a cross-section of a volume mesh. The vector at a point P of the grid is interpolated using the vectors at the nodes of the cell that contains P. This class is derived from PoMesh3DVecCrossSection and may be much more time consuming when choosing a very small grid spacing. For each point of the grid, this class uses a probe tool to find out which cell contains the point. This class behaves like PoMesh3DVecCrossSection if the grid spacing is null. The following image shows a transparent skin, a cross contour, and a vector field representation mapped onto the same plane as the cross-contour.

Figure 2.51. Volume mesh representation node classes

Representations Common to Surface and Volume Meshes

The following visualization nodes may apply to surface or volume meshes (indentation shows class derivation):

Common mesh representation node classes

Visualization of a surface that connects several streamlines starting from a list of aligned sources. The following image represents a transparent skin and a stream-surface colored according to the velocity at the points of the surface.

Abstract class that allows animation of particles along a list of streamlines. Of course, the velocity of the particle motion is relative to the velocity on the streamlines. This class allows some control over the animation. For example, you can specify a time step, the number of frames in the animation, etc.

+ PoStreamTadpoleMotion

Visualization of animated particles that look like a “tadpole.” Each
 particle is drawn with a line segment of three points. The length of the segment is
 proportional to the velocity.

![Common mesh representation node classes](UserGuide_Images/UsersGuide-518.png)
+ PoStreamLineMotion

Visualization of animated particles along streamlines. Each streamline
 is drawn with one color but some points of it are drawn with another color. This other color
 moves along the streamline, and so does the animation.

![Common mesh representation node classes](UserGuide_Images/UsersGuide-519.png)
+ PoStreamPointMotion

Visualization of animated particles. Each particle is represented by a
 simple point.

![Common mesh representation node classes](UserGuide_Images/UsersGuide-521.png)
+ PoStreamSphereMotion

Visualization of animated particles. Each particle is represented by a
 sphere. The animation of these spheres can be slow.

![Common mesh representation node classes](UserGuide_Images/UsersGuide-522.png)

Abstract class to visualize a cell of a mesh. It can be useful for seeing some details of the geometry of a mesh, especially on a non-structured mesh. The cell to draw is specified by its index in the mesh. Note that the cell to draw can be determined by a callback triggered by the probe class PoMeshProbePoint.

* PoCellEdges

Visualization of the edges of a cell.
* PoCellFacets

Visualization of the facets of a cell. For a surface cell, it only fills
 the cell; for a volume cell, it fills the skin of the cell.
* PoCellIndices

Visualization of 2D text strings that indicate the index of the cell
 (drawn at center of the cell) and the indices of each node of the cell (drawn near each node
 position).

Class that does not draw anything, but triggers four kinds of callbacks depending on changes to its position field. Each callback passes the cell that contains the position as parameter argument. The first callback is triggered each time the probe leaves the mesh (position is out of the mesh, and it was inside before). The second callback is triggered each time the probe enters the mesh (position is inside the mesh and was out before). The third callback is triggered each time the probe moves to a different cell (position was in another cell before). The last callback is triggered each time the position changes. It can be very useful to connect the position field to an Open Inventor dragger. Figure 2.52. Common mesh representation node classes

Data-to-Color Mapping

MeshViz includes the following property classes which allow you to map a floating value to a color, or to map a set of floating values to a color ramp or several color ramps. Two ways are available to define a data-to-color mapping:

  • You can instantiate a class derived from PoDataMapping and add this object to the scene graph.
  • You can instantiate a class derived from PbDataMapping and call setDataMapping() to connect this data-mapping object to a visualization node. For example, setDataMapping() is available with PoMesh, PoValueLegend, etc.

See also the the section called “Property and Visualization Classes”, PoDataMapping or PbDataMapping
.

Two values, value1 and value2, are associated with color1 and color2, and transparency1 and transparency2, respectively. The color associated with a value between value1 and value2 is a linear interpolation between color1 and color2. In the same way, the associated transparency is a linear interpolation between transparency1 and transparency2. For instance, the following lines define the color-data mapping below:

Example : Defining a linear data mapping

PoLinearDataMapping* myDataMapping = new PoLinearDataMapping;
myDataMapping->value1 = 0.0;
myDataMapping->color1 = SbColor( 1, 0, 0 );
myDataMapping->value2 = 10.;
myDataMapping->color2 = SbColor( 0, 0, 1 );

Using the setColorFunction() method, you provide a function that returns an SbColor, given a floating value as an input parameter. Each time MeshViz needs to map a floating value to a color, it will call this function. In the same way, the setTransparencyFunction() method provides a function that returns a transparency, given a floating value as an input parameter. Each time MeshViz needs to map a floating value to a transparency, it will call this function.

This class defines a set of colors or a set of color ramps associated with floating values. You can choose:

+ LINEAR_PER_LEVEL type of mapping for a floating value **f**. If **f** is in the interval
 **f** i, **f** i+1, its associated color will be the linear
 interpolation between **c** i and **c** i+1 RGB or HLS colors. In this case, you must
 provide the same number of floating values as the number of colors.
+ NON_LINEAR_PER_LEVEL type of mapping for a floating value **f**. If **f** is in the interval
 **f** i, **f** i+1, its associated color will be the **c** i+1 th RGB or HLS color; no interpolation is
 performed. If **f** is smaller than **f** 1, then **c** 1 is used. In this case, you must provide n+1
 colors for n floating values.

Example : Defining a data mapping with several colors

```

float values[5] = {0.0, 2.5, 5., 7.5, 10.}; SbColor colors[5] = { SbColor(0.0,0.0,1.0), SbColor(0.0,1.0,1.0), SbColor(0.0,1.,0.), SbColor(1.0,1.0,0.0), SbColor(1.0,0.0,0.0) }; PoNonLinearDataMapping2 *myDataMapping = new PoNonLinearDataMapping2; myDataMapping->color.setValues(0,5,colors); myDataMapping->value.setValues(0,5,values); myDataMapping->type = PoNonLinearDataMapping2::LINEAR_PER_LEVEL;

``` The data mapping nodes also allow you to specify threshold values associated with colors. You can specify a minimum threshold or a maximum one using PoDataMapping::minThreshold and PoDataMapping::maxThreshold fields. All values smaller than the minimum threshold are associated with the specified color and, in the same way, values greater than the maximum threshold will be associated with the color of this maximum value.

The threshold effect can be activated and deactivated using the PoDataMapping::maxThresholdEnabled and PoDataMapping::minThresholdEnabled fields.

Handling Undefined Values

Sometime it can be useful to visualize meshes that contain some nodes which have a very large or very small value compared to the range of the other nodes values. It can be nodes where no calculation, measurement, or probe has been realized. It can be a way to indicate that the scalar value at a node is not assigned, or is not significant for visualization. In the following discussion, we call these special values “undefined values.”

MeshViz provides two ways of handling theses undefined values using the PoDataMapping nodes (or PbDataMapping ):

  • You can visualize the cells, or any shapes that contain at least one undefined value, with a specific color and/or transparency.
  • You can discard these cells or shapes from the scene graph. To do that, you must specify in the data-mapping object what are “undefined values.” MeshViz considers any value to be undefined if it is greater than an upper threshold or less than a lower threshold. The upper threshold is set by the field PoDataMapping::maxThreshold and the lower one is set by PoDataMapping::minThreshold. Furthermore, a threshold is activated only if PoDataMapping::maxThresholdEnabled or minThresholdEnabled is TRUE (FALSE by default).

To summarize, a value V is undefined in the following cases:

  • minThresholdEnabled and maxThresholdEnabled are TRUE, and V is not inside the open interval minThreshold, maxThreshold.
  • minThresholdEnabled is TRUE, and V is lower than or equal to minThreshold.
  • maxThresholdEnabled is TRUE, and V is greater than or equal to maxThreshold. To visualize an undefined value with a specific color, just assign the fields PoDataMapping::maxThresholdColor or PoDataMapping::minThresholdColor.

To visualize an undefined value with a specific transparency, just assign the fields:

PoDataMapping::maxThresholdTransparency or PoDataMapping::minThresholdTransparency, and assign the field transparencyEnabled to TRUE.

If you want to discard from the scene graph each cell or shape that
contains an undefined value, set these transparencies to a full value, i.e. a value greater
than PoDataMapping::transparencyValueDeletedParts(0.95 by default).

The following example (located in $OIVHOME/src/MeshViz/Mentor) visualizes a rectangular mesh; each cell that contains one or more undefined nodes will be discarded.

Example : A rectangular mesh with undefined values

// tutorialMesh01.cxx
int
main( int, char** argv )
{
// Initialize Inventor and Xt
Widget myWindow = SoXt::init( argv[0] );
if ( myWindow == NULL )
exit( 1 );
// Initialize MeshViz
PoMeshViz::init();
// Read back from file mesh data
// and geometry
int num_x, num_y;
float *xm, *ym, *vm, vmin, vmax, undef;
read_mesh( "UNDEFGRID.TOPO", num_x, &xm, num_y, &ym );
read_val( "IDESUNI.DAT", num_x\* num_y, &vm, vmin, vmax, undef );
// Define data mapping
PoLinearDataMapping* myDataMapping = new PoLinearDataMapping;
myDataMapping->color1 = SbColor( 1, 0, 0 );
myDataMapping->value1 = vmin;
myDataMapping->color2 = SbColor( 0, 1, 1 );
myDataMapping->value2 = vmax;
myDataMapping->maxThreshold = undef;
myDataMapping->maxThresholdEnabled = TRUE;
myDataMapping->maxThresholdTransparency = 1.0;
myDataMapping->transparencyEnabled = TRUE;
// Initialize the mesh
PoParalCartesianGrid2D* mesh = new PoParalCartesianGrid2D;
mesh->setGeometry( num_x, num_y, xm, ym );
mesh->addValuesSet( 0, vm );
// Create the solid contour visualization node.
PoMeshFilled* myFill = new PoMeshFilled;
myFill->valuesIndex.setValue( 0 );
myFill->coloringType = PoMesh::COLOR_MAPPING;
SoSeparator* root = new SoSeparator;
root->ref();
root->addChild( mesh );
root->addChild( myDataMapping );
root->addChild( myFill );
SoXtExaminerViewer* viewer = new SoXtExaminerViewer( myWindow );
viewer->setSceneGraph( root );
viewer->setBackgroundColor( SbColor( 1., 1., 1. ) );
viewer->show();
SoXt::show( myWindow );
SoXt::mainLoop();
return 0;
}

To visualize undefined cells in gray, just replace the two lines:

myDataMapping->maxThresholdTransparency = 1.0;
myDataMapping->transparencyEnabled = TRUE;

by:

myDataMapping->maxThresholdColor = SbColor( 0.2, 0.2, 0.2 );

Defining Isovalues

If you want to do solid or line contouring, you must specify which values you want to display. MeshViz provides the PbIsovaluesList and PoIsovaluesList classes that allow you to do so. There are two ways to define a list of isovalues:

  • You can instantiate a class derived from PoIsovaluesList and add this object in the scene graph.
  • You can instantiate a class derived from PbIsovaluesList and call setIsovaluesList() to connect this object to a visualization node. For example, setIsovaluesList() is available with PoMesh, PoValueLegend, etc.

See also the the section called “Property and Visualization Classes” A list of isovalues can be a list of any floats. However, convenience methods are available to define a regular list. In a regular list, the step size between two consecutive isovalues is a constant. For example, the following methods are available for creating lists:

  • void setRegularIsoList(int numFloats, const float *values, int numValues)
  • void setRegularIsoList(int numValues, float firstValue, float step)
  • void setRegularIsoList(float min, float max, int numValues)

Example : Creates a regular list of 25 isovalues bounded by 0 and 10

PbIsovaluesList myIsoList;
myIsoList.setRegularIsoList( 0., 10., 25 );

or:

PoIsovaluesList* myIsoList = new PoIsovaluesList;
myIsoList->setRegularIsoList( 0., 10., 25 );

:_0_8_12 Example : Defines a non-regular list that contains three isovalues: 0 8 12

float values[3] = { 0, 8, 12 };
PbIsovaluesList myIsoList;
myIsoList.setIrregularIsoList( 3, values );

or:

float values[3] = { 0, 8, 12 };
PoIsovaluesList* myIsoList = new PoIsovaluesList;
myIsoList->isovaluesList.setValues( 0, 3, values );

The isovalue list may be used by the following visualization
nodes:* PoMeshContouring to visualize isolines of a mesh.