Volumetric mesh generation is a complex topic and several tools exists to perform this task such as: GID, CGAL or Gmsh. We choose to use the C++ library CGAL
(CGAL) as a dedicated plug-in for Sofa exists. Volumetric mesh can be computed either using a surface mesh or an image. Whatever the input, we need to add the CGALPlugin
with the following line:
rootNode.createObject('RequiredPlugin', pluginName='CGALPlugin')
All the components that will help to build the volumetric mesh will be placed in a child node, this is performed with
node = rootNode.createChild('node')
Then, we need to load the surface mesh that will be used as input for CGAL. Many file formats are supported (OBJ
, VTK
, STL
…). In our example, a STL file has been produced using some CAD software. This file is then loaded with:
node.createObject('MeshSTLLoader', name='mesh', filename=path+'finger.stl')
And then the magic is performed with the MeshGenerationFromPolyhedron
where four parameters are used to control the meshing:
cellSize
: this parameter controls the size of mesh tetrahedra. It provides an upper bound on the circumradius of the mesh tetrahedrafacetAngle
: This parameter controls the shape of surface facets. Actually, it is a lower bound for the angle (in degree) of surface facets. When boundary surfaces are smooth, the termination of the meshing process is guaranteed if the angular bound is at most 30 degreesfacetAngle
: this parameter controls the shape of surface facets. Actually, it is a lower bound for the angle (in degree) of surface facets. When boundary surfaces are smooth, the termination of the meshing process is guaranteed if the angular bound is at most 30 degreescellRatio
: this parameter controls the shape of mesh cells. Actually, it is an upper bound for the ratio between the circumradius of a mesh tetrahedron and its shortest edge. There is a theoretical bound for this parameter: the Delaunay refinement process is guaranteed to terminate for values larger than 2facetApproximation
: the approximation error between the boundary and the subdivision surface. It provides an upper bound for the distance between the circumcenter of a surface facet and the center of a surface Delaunay ball of this facetIt may require some trials and errors to find a good set of parameters that capture well the details of the surface mesh without leading to a large number of tetrahedra. The framerate of the simulation is quite sensitive to the setting of these parameters. If the simulation is running to slow consider changing them in order to reduce the number of tetrahedra. For our example, the set of parameters is:
node.createObject('MeshGenerationFromPolyhedron', name='gen', template='Vec3d', inputPoints='@mesh.position', inputTriangles='@mesh.triangles', drawTetras='1',
cellSize="10",
facetAngle="30",
facetSize="4",
cellRatio="2", #Convergence problem if lower than 2
facetApproximation="1"
)
The computed tetrahedra are then stored in a mesh container for later usage with:
node.createObject('Mesh', position='@gen.outputPoints', tetrahedra='@gen.outputTetras')
Mind the fact that the syntax used links the output of the generator ‘gen’ to the created ‘Mesh’ object using ‘@’. After that you may export the resulting volumetric mesh with the following line for further use:
node.createObject('VTKExporter', filename=path+'finger', edges='0', tetras='1', exportAtBegin='1')
We want to export only the tetrahedra (no edges, no triangles) and we want a single export that is performed at the beginning of the simulation (a single export is needed since the mesh will not deform during this simulation).
For an interactive feedback of what has been computed by CGAL
, we can use this line:
node.createObject('OglModel', filename=path+"finger.stl", color="0.0 0.7 0.7 0.5")
It will superimpose the surface mesh on the volumetric mesh.