MeshViz FAQs

If you don't find what you are looking for here, check the Mercury TGS Series website (3dviz.mc.com) as a more recent version of this FAQ may be posted there.


Documentation/Resources

  1. Where can I get information about MeshViz ?
  2. What printed documentation is available to help me get started using MeshViz ?


General Reference Info

  1. What is MeshViz in relation to Open Inventor?
  2. Can MeshViz be used without Open Inventor?
  3. How do I initialize MeshViz ?
  4. Can I call PoMeshViz::init() several times?
  5. How do I find out the parts in the catalog of a MeshViz nodekit?
  6. How can I retrieve the Open Inventor nodes built by a MeshViz nodekits?
  7. How can I have different parts of my graphic window working in different world coordinates?


Inventor files with MeshViz

  1. The SceneViewer supplied with the Open Inventor distribution is not able to read my Inventor file containing MeshViz nodes. What can I do?
  2. What are the differences between FOLD NODE_WRITE_FORMAT and UNFOLD_NODE_WRITE_FORMAT?
  3. How can I build a SceneViewer that is able to read Inventor files that contain MeshViz nodes?


Charting with GraphMaster

  1. Why is the text on my axis very tiny?
  2. Why does MeshViz use a domain (PoDomain) instead of a classic scale (SoScale)?
  3. I use a PbDomain but my axis labels are still very small. Why?
  4. How can I generate an axis representation that is not square?  
  5. How can I preserve the aspect ratio of my data while using a domain?
  6. How can I use Open Inventor shapes (SoCube/CoCone,…) and MeshViz shapes when I use a PoDomain?
  7. Why do SoFont nodes inserted just before my axis seems to be ignored?
  8. How can I change the numeric format of the graduations of my axis/legend/pie chart/histograms/…?


Mesh visualization with 3DdataMaster

  1. What kinds of data can I define on a surface/volume mesh?
  2. What kinds of meshes can 3DdataMaster handle?
  3. How do I define a surface/volume mesh?
  4. How do I define a representation on a surface/volume mesh?  
  5. Can I retrieve information about the connectivity of my mesh?
  6. What are the steps for generating a mesh representation?
  7. Can I display several data sets at the same time on a mesh?
  8. Can I display several meshes at the same time?
  9. How can I avoid the duplication of the data of my mesh?
  10. How do I interpolate a value from any point in the space mesh?
  11. How do I retrieve the coordinates of the points of a level surface (isosurface)?
  12. How do I select a cell of a mesh?
  13. How do I display my data using color?
  14. How do I define a data mapping that uniformly covers a range of colors?
  15. How do I specify an altitude on a 2D mesh in order to represent an elevation?
  16. How do I exclude some cells (undefined cells) in a mesh representation?
  17. How do I create an animation of the data of a mesh?
  18. How do I generate an animation of the geometry of a mesh?
  19. How do I represent a fault?
  20. Can I visualize several cross-sections at the same time?
  21. How do I retrieve the Pbxxx mesh object associated with my PoMeshProperty node?
  22. How do I retrieve the bounding box of a mesh?
  23. Can I annotate contour lines?

Documentation/Resources

  1. Where can I get information about MeshViz?

    You can get information from:
  2. What printed documentation is available to help me get started using MeshViz?

    The Open Inventor by Mercury User’s Guide: The chapter MeshViz is designed to help you understand how to use GraphMaster, and 3DdataMaster class libraries. Source code for the book examples is provided with the MeshViz distribution so that you can run (and experiment with) the example programs that you are reading about in the book.



General Reference Info

  1. What is MeshViz in relation to Open Inventor?
    MeshViz is a set of C++ classes which implement powerful extensions to Open Inventor.

    Open Inventor allows users to create basic 3D drawings using polygons, polylines, markers, and NURBS curves and surfaces with many kinds of data mapping (colors, textures,…). MeshViz, in contrast, has “built-in” nodes that use Open Inventor basic shapes to create high level representations for charting (3D axes, curves, histograms, pie charts, legends,...) and scientific visualization (2D/3D meshes represented using contour lines, isosurfaces (known as “level surfaces” in MeshViz), cross sections, streamlines,…).



  2. Can MeshViz be used without Open Inventor?

    No. First, MeshViz is an extension of Open Inventor. Almost all MeshViz classes derive from Open Inventor classes.

    Second, MeshViz does not contain a viewer or render area class for rendering a scene graph, nor does it contain group nodes (SoGroup classes) for building a scene graph. For at least these two reasons, MeshViz cannot be used without Open Inventor.



  3. How do I initialize MeshViz?

    It is very easy. Simply call the method PoMeshViz::init(). Note that calling this method also calls SoDB::init() and SoNodeKit::init().



  4. Can I call PoMeshViz::init() several times?
    Sure. Calling this method several times will do no harm; no extra overhead is involved.



  5. How do I find out the parts in the catalog of a MeshViz nodekit?
    The question “How can I retrieve the Open Inventor nodes built by a MeshViz nodekits?” addresses this problem for all parts updated during an action. For others parts, you can find out about them as you would with any other Inventor nodekits (see “Macros for Getting Parts,” page 371 in The Inventor Mentor book).



  6. How can I retrieve the Open Inventor nodes built by a MeshViz nodekits?
    MeshViz nodekits create Open Inventor nodes in order to realize their own representation. For instance, a PoPieChart nodekit (for building a pie chart) creates a list of SoFaceSet nodes for each slice of the pie chart and stores them in its catalog (see Nodekit catalog, page 363 of The Inventor Mentor).

    If you need to consult these nodes, they must be available (i.e. have been created). This normally happens on the first traversal of the nodekit. The callback set by the PoBase::addPostRebuildCallback() method is called as soon as these nodes are available.
    For instance, if you want to retrieve the SoFaceSet of the first slice you must do the following:
    PoPieChart3D *pieChart3D = new PoPieChart3D;
    pieChart3D->addPostRebuildCallback(pieChartRebuildCB, NULL);
         
    void pieChartRebuildCB(void *userData, PoBase *base)
    {
      PoPieChart3D *myPieChart = (PoPieChart3D *) base;
         
      // Retrieve the part named "slice".
      SoGroup *sliceGroup = (SoGroup*)myPieChart->getPart("slice",      FALSE);
         
      if (sliceGroup) {
        SoFaceSet *firstSliceFaceSet = NULL;
         
        // Search the first SoFaceSet if it exists.
        for (int i = 0; i <  sliceGroup->getNumChildren(); i++) {
          if (sliceGroup->getChild(i)->isOfType(SoFaceSet::getClassTypeId())) {
            firstSliceFaceSet = sliceGroup->getChild(i);
            break;
          }
        }
         
        if (firstSliceFaceSet) {
          // You can now work with the face set
    // corresponding to the first slice } }
    }
  7. How can I have different parts of my graphic window working in different world coordinates?

    MeshViz provides an elegant way to specify several cameras in the same scene graph. The PoSceneView nodekit offers this capability.

    A PoSceneView is defined by a camera, a viewport specified in normalized window coordinates, and a scene graph. This allows each PoSceneView to work in its own world coordinates.
    As usual, the viewer will attach to the first camera it finds in the scene graph. You can also switch the viewer from one camera to another by calling SoXtViewer::setCamera(). There is no automatic mechanism to switch the viewer from one PoSceneView’s camera to another.

    The following figure illustrates the use of PoSceneView:
 


The associated scene graph is:

 




Inventor files with MeshViz

  1. The SceneViewer supplied with the Open Inventor distribution is not able to read my Inventor file containing MeshViz nodes. What can I do?

    The question “How can I build a SceneViewer that is able to read Inventor files that contain MeshViz nodes?” addresses this problem.



  2. What are the differences between FOLD_NODE_WRITE_FORMAT and UNFOLD_NODE_WRITE_FORMAT?

    Use method PoBase::setNodeWriteFormat() to select one of these modes. These modes specify the way MeshViz nodes are stored in a file when you use Open Inventor SoWriteAction.

  3. How can I build a SceneViewer that is able to read Inventor files that contain MeshViz nodes?

    We must distinguish two cases:


Charting with GraphMaster

  1. Why is the text on my axis very tiny?

    The size of the text on your axis is expressed as a percentage of the domain. This is also true for certain other axis attributes and other representations. Either you have forgotten to define a domain (PoDomain), or you have not defined it correctly.



  2. Why does MeshViz use a domain (PoDomain) instead of a classic scale (SoScale)?

    There are several reasons for the existence of the domain.

    First imagine that you have a curve that ranges from 0 to 1 along the x-axis and from 0 to 1000 in the y-axis. You want to represent this curve and also the axis system associated with it.

    If you don’t use a transformation, the resulting display will not be legible because the y-axis is very large compared to the x-axis. Intuitively you will want to scale the y-axis relative to the x-axis (or vice versa) in order to obtain something legible. If you do this using an SoScale, it will work for the curve representation (PoCurve) but you will have some problems with the axis representation (PoLinearAxis). Specifically, you will note that the graduation labels as well as the arrow at the end of the axis will appear very flattened along the direction of the Y-axis. So, applying a simple scale transformation is not the correct way to achieve a good result because some parts of your representation need to be uniformly scaled but not others.

    The property node PoDomain addresses these kinds of problems.

    Second, many fields of MeshViz nodekits are expressed in the space defined by the current domain. Chapter “5.1.4 Domain” of the MeshViz User’s Guide provides additional details about the use of domains.



  3. I use a PbDomain but my axis labels are still very small. Why?

    You have used the deprecated method PoBase::setDomain(). We recommend that you use the property node PoDomain instead.

    However, if you want to continue to use the previous method, the problem is probably that your PbDomain object passed to the PoBase::setDomain() method is declared local to a function. When the function is exited, the PbDomain object is deleted. In order to preserve the integrity of your data, your axis is informed of the deletion, and uses the values of the default constructor of PbDomain.

    To solve this problem you can do any of the following:
  4. How can I generate an axis representation that is not square?
    Generally, you define the domain values as the bounding box of your data and you obtain a square representation.
    For instance, if you want to have an X-axis from 0 to 1 and a Y-axis from 0 to 10, you set the domain (PoDomain) fields to: min (0,0,0) and max (1,10,1).



    Now, if you want to obtain an X-axis which is double the size of the Y-axis, you must define a domain which has double the size of the Y-data -- that is, min (0,0,0) and max (1,20,1) -- and you obtain the following:



    In the first case (square representation), the scale applied by the PoDomain to the axis is the following:

    min and max are the fields of the PoDomain node.

    dx = max[0] - min[0]
    dy = max[1] - min[1]
    dz = max[2] - min[2]

    Sx = 1: the end coordinate of the X-Axis is 1.
    Sy = dx/dy = 1 / 10 = 0.1 -> the top coordinate of the Y-Axis is 10 x 0.1 = 1.
    Sz = dx/dz = 1 / 1   = 1


    In the second case (rectangular representation), the scale applied by the PoDomain to the axis is the following:

    Sx = 1 : the end coordinate of the X-Axis is 1.
    Sy = dx/dy = 1 / 20 = 0.05 -> the top coordinate of the Y-Axis is 10 x 0.05 = 0.5
    Sz = dx/dz = 1 / 1   = 1



  5. How can I preserve the aspect ratio of my data while using a domain?
    As described in the previous question, defining the domain values as the bounding box of your data gives a square representation. However if you absolutely need to preserve the aspect ratio of your data, you can use the PoDomain::setValues() method with the last argument set to MIN_BOUNDING_CUBE.

    For instance, if you want to have an X-axis from 0 to 1 and an Y-axis from 0 to 5, and preserve the original (1 to 5) aspect ratio:

    myDomain->setValues(SbVec3f(0,0,0), SbVec3f(1,5,1), PoDomain::MIN_BOUNDING_CUBE);





  6. How can I use Open Inventor shapes (SoCube/CoCone,…) and MeshViz shapes when I use a PoDomain?
    All MeshViz shapes automatically insert in their catalog kit (part named domainTransform) a transformation which corresponds to the domain, so these shapes are automatically transformed. For Open Inventor shapes, you must add this transformation to the scene graph manually just before the shape to be transformed. To get the transformation that should be applied, call the PoDomain::getMatrixTransform() method which returns an SoMatrixTransform.



  7. Why do SoFont nodes inserted just before my axis seems to be ignored?
    All MeshViz representations ignore the node SoFont for selecting the font name and size. Instead the property node PoMiscTextAttr is used for this purpose.



  8. How can I change the numeric format of the graduations of my axis/legend/pie chart/histograms/…?
    The property node PoNumericDisplayFormat manages the format of all numeric values displayed by MeshViz. Insert this node with the requested format in the scene graph just before the representation to be configured.


Mesh visualization with 3DdataMaster

  1. What kinds of data can I define on a surface/volume mesh?
    3D vectors or floating values can be defined at each node of a surface/volume mesh. The methods addValuesSet() and addVecsSet() of each mesh (inheriting from PoMeshProperty or PbMesh) allow you to define these sets of values/vectors.



  2. What kinds of meshes can 3DdataMaster handle?
    For 2D (or surface) meshes, you can define the following kinds of meshes:

  3. How do I define a surface/volume mesh?

    A surface/volume mesh is defined by one of the classes deriving from PoMeshProperty. The class names of surface meshes are suffixed by 2D (for instance, PoCartesianGrid2D) and the class names of volume meshes are suffixed by 3D (for instance, PoCartesianGrid3D).

    Each of these classes contains a method setGeometry() for setting the geometry of the mesh and methods addValuesSet() and addVecsSet() for adding a set of data.

    Adding such a node in a scene graph does not render anything. It just sets the current mesh used by the representation nodes (inheriting from PoMesh).

    Another way (less used) using the PbMesh classes is described in the question “How can I avoid the duplication of the data of my mesh?”.



  4. How do I define a representation on a surface/volume mesh?

    All of the classes deriving from PoMesh allow you to define a mesh representation (such as a level surface (isosurface), a contour line,…). Such a node uses the current mesh for computing its representation, so it must be set in the scene graph after a PoMeshProperty node.



  5. Can I retrieve information about the connectivity of my mesh?

    The PbMesh class has methods that allow you to retrieve information about the connectivity of your mesh, such as the list of cells that own a node or the list of cells adjacent to a node or face, including

  6. What are the steps for generating a mesh representation?
    The following steps allow you to generate a mesh representation:

    1. Create a mesh node corresponding to your mesh topology from a class deriving from PoMeshProperty.

    2. Set the geometry and the data on your mesh.

    3. Add your mesh node to your scene graph.

    4. (Optional step)
      Some representations require that isovalues be specified. In this case, create a PoIsovaluesList node, specify the list of isovalues, and add this node to your scene graph.

    5. (Optional step)
      To color your representations, use a PoDataMapping node to make the association between floating point values and colors. This node must be configured and added to the scene graph.

    6. Create the desired representation inherited from PoMesh with your attributes and add it to the scene graph.



  7. Can I display several data sets at the same time on a mesh?
    It’s not a problem to display several data sets on the same mesh. Define your mesh node with a class inheriting from PoMeshProperty, then add as many sets of values/vectors as you want to display with the methods addValuesSet() and addVecsSet(). Add this node to your scene graph. Now add to the scene graph the representation that you wish (classes inherited from PoMesh) and specify with the fields valuesIndex and vecsIndex the set of data that each representation should use.



  8. Can I display several meshes at the same time?
    Yes. The node that defines a mesh (PoMeshProperty and derived classes) and the node(s) that draw representations of it (PoMesh and derived classes) are related in much the same way as an SoCoordinate3 node and an SoFaceSet node are related in Inventor. A mesh node and a coordinate node both put data into the traversal state, which is inherited by a representation (“rep”) node or a geometry node (respectively).

    One mesh node may be used by more than one rep node; a rep node may be multiply instanced to display more than one mesh; or the scene graph may contain multiple sub-graphs, each with its own mesh and rep(s).



  9. How can I avoid the duplication of the data of my mesh?
    MeshViz provides two sets of classes for defining meshes. The mesh nodes (nodes inheriting from PoMeshProperty) are generally recommended because your data is written out when the scene is written to an Inventor file. However, these nodes always make a copy of your data. To avoid this copy, you must use the mesh object (see PbMesh). All PbMesh constructors take a Boolean flag (default TRUE) that specifies if the data should be duplicated. Because mesh objects are not part of the scene graph, the data is not automatically inherited by mesh representation nodes. You must use a PoMesh node and call its setMesh method with your mesh object.



  10. How do I interpolate a value from any point in the space mesh?
    The PbMesh::findContainingCell() method retrieves from a 3D point the mesh cell which contains the point and also parametric coordinates of the point in the containing cell. The PbCell::getValue() method retrieves the interpolated scalar value from parametric coordinates.



  11. How do I retrieve the coordinates of the points of a level surface (isosurface)?
    There is no direct way to retrieve these coordinates. The only way is to retrieve the SoCoordinate3 generated in the part named groupLevelSurf of the PoMeshLevelSurf catalog part. The question “How can I retrieve the Open Inventor nodes built by MeshViz nodekits?” explains how to do this.



  12. How do I select a cell of a mesh?
    The following process describes a way of selecting a cell of a mesh:

    In the case of picking of the skin, the coordinates of the picked point must be translated inside the mesh using the negative normal of the picked face of the skin (this normal can be retrieved with the getNormal() method of the class SoPickedPoint; see Chapter 10 “Handling Events and Selection” of The Inventor Mentor for more details about selection)

  13. How do I display my data using color?
    We have already seen (see “How do I define a surface/volume mesh?”) that a mesh is defined by some geometry and by one or several set(s) of values. The problem is now to make the link between these values and colors. This is the role of data mapping which associates a color with a given value. The base class for data mapping is PoDataMapping; the derived classes (PoLinearDataMapping, PoNonLinearDataMapping, and PoNonLinearDataMapping2) allow different way of specifying it.

    All representations that need coloring (different from COLOR_INHERITED, which uses the current color) use the current data mapping.



  14. How do I define a data mapping that uniformly covers a range of colors?

    To define a data mapping that uniformly covers the chromatic circle of colors from a set of values bounded by a min and a max value, use PoLinearDataMapping2 as follow:
         
    min is the minimum value of the values set.
    max is the maximum value of the values set.
         
    // Blue, Cyan, Green, Yellow and Red
    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 *dataMapping = new PoNonLinearDataMapping2;
    dataMapping->type = PoNonLinearDataMapping2::LINEAR_PER_LEVEL; deltaValue = (max – min) / 4.0; float val = min; for (int i = 0; i < 5; val += deltaValue, i++) { dataMapping->value.set1Value(i,val); dataMapping->color.set1Value(i,colors[i]); }
    This graphic is the interpretation of the previous code:


  15. How do I specify an altitude on a 2D mesh in order to represent an elevation?
    We have already seen (see “How do I define a surface/volume mesh?”) that a mesh is defined by some geometry and by one or several set(s) of values. All representations on a 2D mesh inherited from PoMesh2D contain a field named zValuesIndex which indicates the index of the value set from the current mesh that will be used for the elevation.



  16. How do I exclude some cells (undefined cells) in a mesh representation?
    Sometimes meshes contain nodes that have very large or very small values compared to the range of the other nodes’ values. Meshes may also have nodes with no measurement or calculation, in which case you must assign them an out-of-range value. We call these special values “undefined values”.

    The data mapping class, PoDataMapping, through the following fields allows you to manage “undefined values”:
  17. How do I create an animation of the data of a mesh?
    The simplest way to create an animation of the data of a mesh is to add all sets of values to the current mesh (class inheriting from PoMeshProperty) with the method addValuesSet() (or addVecsSet() for animation of vector data) (see “How do I define a surface/volume mesh?”) specifying a different index for each set. In the callback that manages your animation, you just need to change the index of the value set (or vector set) used by your representation with the fields valuesIndex or vecsIndex.



  18. How do I generate an animation of the geometry of a mesh?
    The solution is very similar to animating data, but in this case you must call the setGeometry() method on your current mesh (class inheriting from PoMeshProperty) in the callback that manages your animation. Your representation (i.e., the class inheriting from PoMesh) will be automatically updated with your new geometry.

    Another solution, which is less time consuming but uses more memory, consists of adding several meshes with different geometry (class inheriting from PoMeshProperty) under an SoSwitch node, then selecting the child corresponding to your animation step.



  19. How do I represent a fault?
    The representation of faults involves using a 2D mesh, that is, a surface mesh.
    The first step is to create the mesh node that corresponds to your mesh topology.
    For instance if you have a regular Cartesian grid 2D mesh, do the following:
    // zn: data set for elevation.
    // num_x, num_y: size of the grid.
    // xmin,ymin, xmax,ymax: coordinates of the grid.
    PoRegularCartesianGrid2D *po_mesh = new PoRegularCartesianGrid2D;
    po_mesh->mesh.setGeometry(num_x,num_y, xmin,ymin, xmax,ymax);
    po_mesh->addValuesSet(0, zn);
    The second step consists of retrieving the Pbxxx mesh object stored in the node mesh and calling the method PbMesh::getFaultMesh() which builds a new triangle mesh where faults have been inserted.

    Continuing with our example, we have:
    // numFaultLines: number of fault lines.
    // faultLineSizes: the number of points of each fault line.
    // faultLineCoords: the coordinates of each point of the fault lines. const PbMesh2D *mesh2D = (const PbMesh2D *)po_mesh->getMesh(); PbTriangleMesh2D *faultMesh =(PbTriangleMesh2D *) mesh2D->getFaultMesh(numFaultLines, faultLineSizes, faultLineCoords); PoTriangleMesh2D *po_faultMesh = new PoTriangleMesh2D; po_faultMesh->mesh.setValue(*faultMesh);
  20. Can I visualize several cross-sections at the same time?
    Yes, of course! You just need to use as many PoMeshCrossSection objects with different parameters as the number of cross-sections you want.



  21. How do I retrieve the Pbxxx mesh object associated with my PoMeshProperty node?
    The question “How do I retrieve the bounding box of a mesh?” shows you how to retrieve such an object.



  22. How do I retrieve the bounding box of a mesh?
    The PbMesh::getBoundingBox() method allows you to retrieve the bounding box of your mesh. However, to retrieve this bounding box from your mesh node you must first retrieve the associated PbMesh object. For instance, with a PoTriangleMesh2D:
    PoTriangleMesh2D *po_mesh = new PoTriangleMesh2D;
    po_mesh->setGeometry(. . .);
    PbMesh *mesh = po_mesh->getMesh();
    SbBox3f box3f = mesh->getBoundingBox();
  23. Can I annotate contour lines?
    The PoMeshContouring class, which builds contour lines on 2D mesh, contains the following fields to parameterize the display of annotations: