The OpenInventor mesh representation nodes described in Section 2.2.4, “Data Mapping” create a graphical representation of features such as isosurface or skin. But it may be necessary to retrieve these features as a data structure suitable for computation. This process is called Mesh Extraction and is availabe as an independent API described below.
Note: The mesh extraction API is used internally by the Data Mapping API to extract the features from the input mesh before rendering it. Most data mapping nodes return an extractor containing the extracted mesh usable for any post processing task. |
Once all the required interface methods have been implemented in your application’s classes as described in Section 2.2.3, “The abstract mesh interface”, you are ready to start the mesh extraction step.
Mesh Extraction creates a mesh of lower (or equal) dimension from a higher dimension one. For instance, when extracting a surface mesh (2D) representing an isosurface from a volume mesh (3D).
For each type of extraction, a set of extractors are provided usually one per supported mes type. For instance, Isosurface extraction can be done with MiIsosurfExtractUnstructured( C++ | Java ) for unstructured meshes and MiIsosurfExtractRegular for regular meshes. In some cases, the same extractor will work for several mesh types. In this case, several getNewInstance() methods are provided for convenience.
Extractors are also interfaces but they are implemented internally by MeshViz. Thus they cannot be created as normal classes. To create a new extractor, each extractor contains a getNewInstance() method returning a pointer to an extractor interface.
The following example shows how to create an isosurface extractor for an unstructured mesh.
MiIsosurfExtractUnstructured* isosurfExtract = MiIsosurfExtractUnstructured::getNewInstance(mesh);
The returned extractor interface object can then be used to extract one or more meshes from the original one. Using the previously created isosurface extractor, we can now perform the extraction:
const MeXSurfaceMeshUnstructured& isosurf = isosurfExtract->extractIsovalue(isoValue,scalarSet);
As you can see from this example, the result of a mesh extraction is also a mesh but the dimension of the resulting mesh is lower than or equal to the dimension of the original mesh. The isosurface extraction creates a MeXSurfaceMeshUnstructured( C++ | Java ) (2D) set from a MeXVolumeMeshUnstructured( C++ ) (3D).
All extractors return meshes prefixed with MeX (for Extracted Mesh) which are very similar to their Mi parent class but with some additional information such as cell surfaces, face normal, ...
When using structured mesh extractors, you will notice that some extractors create structured meshes similar to the original mesh but some other extractors always create unstructured meshes. This is because some of the algorithms such as isosurface extraction produce irregular toplogies that is not simply a reduction of the original mesh like a logical slice whatever input mesh they are applied on.
Each instance of an extractor contains a single extracted mesh returned by reference. After each extraction, for instance when changing the isovalue, the content of the extracted mesh is replaced by the new one. If you need to keep the old mesh for any reason, you can either create another instance of an extractor or use the getNewClone() method of the extracted mesh to duplicate it. After modifying the input mesh, assuming that the associated time stamps have been updated, calling the extractor with the same parameters as the first time will recompute the topology, geometry and data set extracts. When only the geometry has changed, the topology and data set extracts will not be recomputed. When nothing has changed in the input mesh and cell filter, calling the extract method does nothing.
Two mechanisms are available for detecting that the result of an extract has changed during the last call to extract:
Checking the time stamp of the result: Call the getTimeStamp() method on the components of the result mesh before and after calling the extractor and compare the values. If they have changed, the result mesh has been updated and thus the resulting representation is invalid.
Using the MiExtractorCallback interface: The setExtractorCallback() method of each extractor can be used to set a callback class that will be called when the input mesh needs to be recomputed. Thus you are immediately aware of any change in the result of the extraction. See MiBaseExtractor::setExtractorCallback() for more details.
Before using any of the extraction classes, the MeshViz Extraction toolkit must be initialized by calling the following static method:
MiMeshViz::init();
Similarly, before ending the program, call the following method:
MiMeshViz::finish();
This cleans-up all the resources used.
Notice that this initialization is done automatically when using MeshViz Data Mapping by the MoMeshViz( C++ ) class.
Extracts a surface mesh from a volume mesh on which all points have the same value in the given data set.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
The following sample code shows how to extract the isosurface of value 2.0 from the scalarSet data set attached to a mesh:
MiIsosurfExtractUnstructured* isosurfExtract =
MiIsosurfExtractUnstructured::getNewInstance(mesh);
const MeXSurfaceMeshUnstructured& isosurf =
isosurfExtract->extractIsovalue(2.0,scalarSet);
Extracts a surface mesh from a volume mesh that represents the external boundary of the volume mesh. A face of the input mesh is part of the skin if it belongs only to one cell.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
The parallel optional parameter of the getNewInstance method can be used to turn on multi threaded extractions. In this case, the extractor tries to use a parallel algorithm to speed-up the computation. The default is true (use parallel computation).
The following sample code shows how to extract the skin of a given mesh with attached geometry.
MiSkinExtractUnstructured* skinExtract = MiSkinExtractUnstructured::getNewInstance(mesh); const MeXSurfaceMeshUnstructured& skin = skinExtract->extractSkin();
Extracts a line mesh from a volume or a surface mesh that represents the outline of the mesh. An edge of the input mesh is part of the outline if it belongs only to one cell.
Additional data sets can be mapped onto this extracted line mesh by calling the extractScalarSet() or extractVec3Set() methods.
The following sample code shows how to extract the outline of a given mesh with attached geometry.
MiOutlineExtractUnstructured* outlineExtract = MiOutlineExtractUnstructured::getNewInstance(mesh); const MeXLineMeshUnstructured& outline = outlineExtract->extractOutline();
A logical slice is an extraction method valid only for structured meshes. On this type of mesh, each cell can be accessed through three indices (I,J,K) and similarly for nodes.
A logical slice along I is a surface defined by the nodes (I,J,K) where one of I, J or K is a constant.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
The following shows how to extract a logical slice along J at index 2000:
MiLogicalSliceExtractRegular* logicalSliceExtractJ =
MiLogicalSliceExtractRegular::getNewInstance(mesh);
const MeXSurfaceMeshRegular& logicaSlice =
logicalSliceExtractJ->extractLogicalSlice(SLICE_J, 2000,NULL);
An interpolated logical slice is similar to a logical slice except that the slice value is given as a floating point value. This results in a logical slice being located in between two consecutive logical slices.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
The following shows how to extract an interpolated logical slice along J at value 2000.5 so exactly at equal distance between the logical slices 2000 and 2001:
MiInterpolatedLogicalSliceExtract* interpLogicalSliceExtractJ =
MiInterpolatedLogicalSliceExtract::getNewInstance(mesh);
const MeXSurfaceMeshUnstructured& logicalSlice =
interpLogicalSliceExtractJ->extractInterpolatedLogicalSlice(SLICE_J, 2000.5,NULL);
A plane slice is a surface mesh defined by the intersection of a plane with the input mesh.
The plane is defined by a vector normal to the plane and a distance from the origin to this plane along this normal.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
Since the plane slice algorithm is based on the isosurface extraction, it requires that all the mesh cells implement the isosurface topology methods.
The following sample code shows how to extract a plane slice from a mesh:
MiPlaneSliceExtractUnstructured* planeSliceExtract = MiPlaneSliceExtractUnstructured::getNewInstance(mesh); const MeXSurfaceMeshUnstructured& planeSlice = planeSliceExtract->extractSlice(normal, distance, NULL);
See also the Grid Plane Slice.
A fence slice is a surface mesh defined by the intersection of several arbitrary planes (the fences) with a volume mesh.These fences are defined by a polyline and a direction. Each segment of the polyline is extruded along the direction to form a clipped plane slice. Thus, each fence goes through a segment of the polyline. Each plane slice is clipped by the extrusion of the 2 endpoints of each segment in the direction. The extracted fence slice is an unstructured surface.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
The following sample code shows how to extract a vertical fence slice composed of 3 segments from a mesh:
MiFenceSliceExtractIjk* fsliceExtract = MiFenceSliceExtractIjk::getNewInstance(mesh); MbVec3d pointList[] = { MbVec3d(0,0,0), MbVec3d(0,1,0), MbVec3d(1,1,0) , MbVec3d(1,0,0) }; std::vector<MbVec3d> polyline(pointList,pointList+4); const MeXSurfaceMeshUnstructured& fenceSlice = fsliceExtract->extract(MbVec3d(0,0,1), polyline, NULL);
A cylinder slice is a surface mesh defined by the intersection of a cylinder of infinite length with the input mesh.
The cylinder is defined by a point on its central axis, a vector representing the central axis direction and the radius.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
Since the cylinder slice algorithm is based on the isosurface extraction, it requires that all the mesh cells implement the isosurface topology methods.
The following sample code shows how to extract a cylinder slice from a mesh:
MiCylinderSliceExtractUnstructured* cylinderSliceExtract = MiCylinderSliceExtractUnstructured::getNewInstance(mesh); const MeXSurfaceMeshUnstructured& cylinderSlice = cylinderSliceExtract->extractSlice(center,radius,direction, NULL);
A sphere slice is a surface mesh defined by the intersection of a sphere with the input mesh.
The sphere is defined by a center point and a radius.
Additional data sets can be mapped onto this extracted surface by calling the extractScalarSet() or extractVec3Set() methods.
Since the sphere slice algorithm is based on the isosurface extraction, it requires that all the mesh cells implement the isosurface topology methods.
The following sample code shows how to extract a sphere slice from a mesh:
MiSphereSliceExtractUnstructured* sphereSliceExtract = MiSphereSliceExtractUnstructured::getNewInstance(mesh); const MeXSurfaceMeshUnstructured& sphereSlice = sphereSliceExtract->extractSlice(center,radius, NULL);
A grid plane slice is a surface mesh defined at the intersection of a regular planar mesh with the input mesh. The resulting mesh is evaluated at each node of the regular planar mesh using the probing mechanism.
The parallel optional parameter of the getNewInstance method can be used to turn on multi threaded extractions. In this case, the extractor tries to use a parallel algorithm to speed-up the computation.
The plane is defined by a vector normal to the plane, a distance from the origin to this plane along this normal, and a spacing between each I and J in the plane.
MiGridPlaneSliceExtract* gridPlaneSliceExtract = MiGridPlaneSliceExtract::getNewInstance(mesh,parallel); const MeXSurfaceMeshRegular& gridPlaneSlice = gridPlaneSliceExtract->extractGrid(normal, distance, deltaI, deltaJ, NULL);
When a vector field represents the velocity of a flow, streamlines are curves that are tangent to the velocity. This means that from any point, a streamline is drawn by moving a point along the vector at this point and finding out where the flow now points to. Streamlines are defined at a single instant in the flow.
The following sample code shows how to extract a set of streamlines from a mesh from a set of input points and a given speed:
MbVec3SetI<> startPoint; startPoint.push_back(MbVec3d(0,0,0)); MiStreamlineExtractUnstructured *extract = MiStreamlineExtractUnstructured::getNewInstance(mesh); constconst std::vector<constconst MeXLineMeshCurvilinear*>& streamlineList = extract->extractStreamline(speed,startPoint);
Probing is useful for finding which cell a 3D point is contained in and for getting the value of a data set attached to the mesh at this position. It is also possible to determine if a point is inside or outside the mesh.
The given 3D point can be located anywhere in the 3D space. It does not need to be a node of the mesh.
The following code shows how to get the cell containing the given point and its scalar value:
MbVec3d startPoint(100,10.5,0); MiPointProbeUnstructured* pointProbe = MiPointProbeUnstructured::getNewInstance(mesh); pointProbe->setLocation(startPoint); if (pointProbe->isFound() == true) { size_t cellId = pointProbe->getCellId(); MbVec3d vec = pointProbe->getValue(vecSet); }
The probing mechanism can be a time consuming process. When probing several times at positions close to each other, you can use the moveLocation() method to set the new probing position relative to the previous one. This tells the probe to look around the current position to find the new cell instead of restarting a full search.
Extracts a line mesh from a surface mesh that represents points having the same value in the given data set.
Additional data sets can be mapped onto this extracted line mesh by calling the extractScalarSet() or extractVec3Set() methods.
The following sample code shows how to extract the isolines of value 2.0 from the scalarSet data set attached to a mesh:
MiIsolineExtractUnstructured* isoLineExtract =
MiIsolineExtractUnstructured::getNewInstance(mesh);
std::vector<double>& isovalueList;
isovalueList.push_back(2.0);
const std::vector<const MeXLineMeshUnstructured*>& isolines =
isoLineExtract->extractIsovalue(isovalueList,scalarSet);
Builds the topology of an unstructured surface mesh over cells corresponding to the given indices in the original volume mesh. The geometry of the resulting surface is pointing at the original geometry.
Additional data sets can be mapped onto this extracted surface mesh by calling the extractScalarSet() or extractVec3Set() methods.
The following sample code shows how to extract cell number 2 from a mesh:
MiCellExtractUnstructured* cellExtract =
MiCellExtractUnstructured::getNewInstance(mesh);
std::vector<size_t>& cellIndices;
cellIndices.push_back(2);
const MeXSurfaceMeshUnstructured cell = cellExtract->extractCell(cellIndices);