-
Notifications
You must be signed in to change notification settings - Fork 14
Instructions
To use the DSC method, simply follow these few steps:
It is recommended to use the setup (initialisation, drawing, logging etc.) provided in the DEMO folder (the demo.cpp, user_interface.h, user_interface.cpp and draw.h source files). However, if you want another setup, you can use the default setup as starting point.
The initialisation should contain the following:
- Import (using the
import_tet_mesh_()function) a simplicial complex from a .dsc file. - Optional: Create a new instance of the DesignDomain class (defining the design domain).
- Create a new instance of the DeformableSimplicialComplex class.
- Create a new instance of a velocity function class (for example the one created in step 2).
Create a your own velocity function class which extends the VelocityFunc class. This class should as minimum override the get_name() and deform() functions. The get_name() function should return a string with the name of the velocity function and the deform() function should have the following signature:
-
For each interface node **n** in the dsc-
Calculate a new position **p** according to the velocity function -
Call `set_destination(n, p)`
-
-
Call `deform()`
Three examples of velocity functions can be found in the repository in the DEMO folder: A rotation function (rotate_function.h), a function which smooths the model (average_function.h) and a function which moves the interface in the normal direction (normal_function.h).
Note: If you use the default setup in the DEMO application, you have to add your custom velocity function to the keyboard_() function.
Use the SCGenerator (found in the SCGenerator folder) to generate a .dsc file from a Wavefront .obj file. The SCGenerator has two dependencies; the TetGen library (source code is found in the TetGen folder) and the DSC library. To generate a .dsc file simply call the program from a command line specifying first the output file name and then the input file name with extension .obj.
Note: Several sample .dsc files exists in the data folder.
If your application requires attributes to be stored at each simplex (each node, edge, face or tetrahedron), extend the corresponding attribute class found in attributes.h and give this as a template parameter when instantiating the DeformableSimplicialComplex class instead of the default attribute class. For example, let us say that our application requires a double value called x to be stored at each node. We then extend the NodeAttributes class and add x as a variable to this new class. This could look like this:
template<typename MT>
class MyNodeAttributes: public NodeAttributes<MT> {
double x;
public:
double get_x(){
return x;
}
void set_x(double _x) {
x = _x;
}
};
We then give MyNodeAttributes as a template parameter to the DeformableSimplicialComplex class instead of the default NodeAttributes class:
dsc = new DeformableSimplicialComplex<MT, MyNodeAttributes<MT>>(DISCRETIZATION, points, tets, tet_labels);
When the DeformableSimplicialComplex object is constructed, several parameters are set. These parameters control the min and max edge length, face area and tetrahedral volume. It also determines when the quality of a simplex has reached a minimum level and a degenerate level. These parameters can be changed by calling the set_parameters() function. However, these are also affected by the avg_edge_length parameter given in the constructor.
How do I iterate over all simplices (in use) of a specific type (nodes, edges, faces or tetrahedra)?
The functions nodes_begin() and nodes_end() returns iterators to the beginning and end respectively of a list of all nodes. The same goes for edges, faces and tetrahedra. Here is an example:
void foo(DSC::DeformableSimplicialComplex<>& dsc)
{
for(auto nit = dsc.nodes_begin(); nit != dsc.nodes_end(); nit++)
{
// Do something
// nit.key() returns the key of the node (of type is_mesh::NodeKey)
}
}
Use the functions get_nodes(), get_edges(), get_faces() and get_tets(). As their name suggests they return the simplices adjacent to the input simplex. For example (assuming dsc is an instantiation of the DeformableSimplicialComplex class):
is_mesh::SimplexSet<is_mesh::NodeKey> nids = dsc.get_nodes(tid);
The simplex set nids will contain the four nodes of the tetrahedron with key 'tid' (of type is_mesh::TetrahedronKey).
It is also possible to get the adjacent simplices to a set of simplices:
is_mesh::SimplexSet<is_mesh::NodeKey> nids = dsc.get_nodes(eid);
is_mesh::SimplexSet<is_mesh::FaceKey> fids = dsc.get_faces(nids);
In this example fids will contain the faces adjacent to either of the two nodes adjacent to the edge with key 'eid'.
Finally, there are a few helpful functions such as get_edge() which returns the key to the edge between two nodes with key nid1 and nid2:
is_mesh::EdgeKey eid = dsc.get_edge(nid1, nid2);
Here is some examples on how to use the three set operations (assuming that A and B are simplex sets containing simplices of node keys):
Union of A and B:
is_mesh::SimplexSet<is_mesh::NodeKey> C = A + B;
or
A += B;
The set A without the elements in B:
is_mesh::SimplexSet<is_mesh::NodeKey> C = A - B;
or
A -= B;
The intersection of A and B:
is_mesh::SimplexSet<is_mesh::NodeKey> C = A & B;
As an example on where to use this, we show how to get the link of faces to a node with key nid:
is_mesh::SimplexSet<FaceKey> fids = dsc.get_faces(dsc.get_tets(nid)) - dsc.get_faces(nid);
Furthermore, the get_edge() function shown earlier is equivalent to:
is_mesh::EdgeKey eid = (dsc.get_edges(nid1) & dsc.get_edges(nid2)).front();