A bridge between CgalMesh and dtk

CgalMesh for dtk is the name of an Action de Développement Technologique, aka ADT, that aims at simplifying the use of the Cgal Mesh features so that Inria researchers and engineers can handle them in a quite fast and easy way.

After six months, it appears that using Cgal Mesh features in a runtime fashion is not so straightforward. In order to make it feasible, we have been developping a kind of wrapper on top of Cgal Mesh named cgalMeshBridge. This article details the problem that we tackle and the manner we use to circumvent it.

CgalMesh brief review

Cgal has been developped in the manner of the Standard Template Library (STL) and makes the use of generic programming. Generic programming is based on the notion of concept that tells the methods that a class must implement so as to satisfy the concept. Such classes are called models of the concept.

Cgal Mesh package features several concepts for generation of isotropic simplicial meshes discretizing 3D domains. Among these concepts, the main ones, from a end-user point of view, are:

Mesh Domain that describes the knowledge required on the object to be discretized

Mesh Criteria that encapsulates the criteria to tune the meshing process

It is thus quite simple to create a mesh using only these three concepts. Nevertheless, one can notice the significant amount of lines of code that are needed to write the three lines that do the real job. These additional lines are not straighforward to write for people having few software engineering skills. Moreover, this code is not fully reusable to mesh an object that is not described by an implicit function. In order to make CGal Mesh easier to use by Inria researchers and engineers, it is necessary to provide new ways to handle it. In the current ADT, one of these ways is to resort to the visual programming framework of dtk.

CgalMesh and dtkComposer: impossible union ?

Polymorphic requirements vs generic programming

The dtk visual programming framework, also called dtkComposer, enables:

to draw workflows in a runtime application

to execute these workflows on the local machine or on remote cluster

to save a workflow and insert it into a more complex one

etc.

In the case of CgalMesh, we would like to draw a pipeline, or a composition, that chains a meshing process followed by a mesh refiner then a mesh optimizer as shown in the image below:

The mesher node takes a mesh domain as input data, then transfers a mesh complex to the refiner node that sends this mesh complex to the optimizer. The connexions between the nodes are carried out by edges connecting output ports to input ports. Each of these ports are typed according to the type of the data they handle. In the manner of typed programming languages, connecting two ports that handle different types is not allowed. For instance, an output port sending a string cannot be connected to an input port waiting for a mesh complex. And this where the problem arises since it is therefore unlikely to connect a port handling a mesh complex templated by a polyhedral mesh domain to a port dealing with a mesh complex templated by an implicit mesh domain because they do not handle the same type ! We have to deal with the same issue as far as the input of the mesher node is concerned: we cannot have a unique input port to handle different kinds of mesh domain. Having a port for each kind of mesh domain is not relevant, it would imply to modify the interface of the node every time a new mesh domain is introduced. This issue makes the visual programming inefficient to handle CgalMesh functionalities.

When using object oriented programming, such a difficulty is solved by resorting to a common parent class that is used as unique type for the ports. Unfortunately, when using generic programming paradigm, the notion of concept defines the API that a class must fullfill to be a model of this concept. There is no need of a common parent class even if it is not forbidden. In practice, this is how the three main concepts of CgalMesh were designed so there are no common parent class.

The problem of the chain of template parameters

In the previous section, we pointed out that dynamic polymorphism is not part of the three main concepts of CgalMesh. But another issue lays in the imbrication of the template parameters between the concepts. Let us take a look on the typedef that are written in the first example.

This typedef defines the kind of mesh domain and we notice that this latter has two template parameters, the type of kernel and the type of the implicit function which is itself templated by the kernel.

typedef CGAL::Mesh_triangulation_3<MD>::type Tr;

The above typedef defines the kind of mesh triangulation. This latter relies on the type of the mesh domain as template parameter.

where Input is the type governing the mesh domain, e.g. an implicit function, a polyhedron, a nurbs, etc.

Such a chain of nested template parameters has two main drawbacks:

changing the type of the input modifies the type of all the concepts in the chain.

in a runtime environment, such as the visual programming framework, user cannot make generic pipelines since the type of the nodes and the type of the data that will travel through them would rely on the type of the input and there is no way to forecast all the cases.

From the software engineering point of view, the reasons for such a chain remain unclear since alternate design would have avoid it. Anyway, we had to come up with a solution in order to fullfill the objectives of the work. Hopefully, a feature of the next C++17 standard dealing with polymorphic allocators in STL containers helped us to find a remedy.

Polymorphic allocators

In large software systems, most of the application program consists of non-generic procedural or object-oriented code that is compiled once and linked many times. Allocators in C++, however, have historically relied solely on compile-time polymorphism, and therefore have not been suitable for use in vocabulary types, which are passed through interfaces between separately-compiled modules, because the allocator type necessarily affects the type of the object that uses it.

The last part should remind you some situation we encountered previously, shouldn’t it. To better understand the commonality, let us say that you conceived a class that provides a STL vector of double as return type of an accessor.

Patatra ! You broke the binary compatibility between your library and the codes that use it. Yet, you just tried to improve your library, but to modify its implementation you had to modify its interface just because the allocator is a template parameter of the vector. This is why nobody used allocators and this fits perfectly with what Pablo Halpern says in his paper.

The proposition of Halpern is to replace the default allocator by a wrapper, or a bridge, around a pure abstract class defining the interface for all the derived allocators. Derived classes contain the machinery for actually allocating and deallocating memory according to user’s demand. Here is a very simplified version of this design:

It follows that changing the way the memory is allocated does not modify the interface of the dummyObject and the binary compatibility is preserved. The goal is clearly reached.

Polymorphic mesh domain

We can learn two things from the bridge pattern of the polymorphic allocator:

firstly, the bridge enables to discouple the interface from the implementation.

secondly, the use of the bridge as template parameter enables to keep the same type of the templated class whatever the implementation that is chosen by the user.

Breaking the chain

We can adapt the same strategy in the context of CgalMesh so as to circumvent the issue due to the chain of nested template parameters. Indeed, using the bridge pattern to design a polymorphic mesh domain, we can obtain a single chain of template parameters that do not vary whatever the mesh domain’s implementation.

As the input of the mesh domain (e.g. implicit function, polyhedron, nurbs, etc) is related to the implementation, the new polymorphic mesh domain can only rely on the kernel. We thus have:

Of course, the cgalPolymorphicMeshDomain is a bridge and wraps a pure abstract class that serves as base class for all the implementations. But we will detail it further. For now, let us focus on the consequence of such a design on the rest of the chain.

In the manner of the polymorphic allocator, the polymorphic Mesh Domain used as template parameter enables to keep the same type for all the concepts that rely on it. We can now design separately-compiled modules that can exchange data that always have the same type.

Hence, provided we suceed in implementing it, the polymorphic Mesh Domain fullfills the requirements that the visual programming framework imposes to use Cgal Mesh.

The Bridge

The proposed solution aims at discoupling the implementation of any mesh domain classes (governed both by the input data and the way this data is treated) from the interface defined by the concept of Mesh Domain. In order to achieve this, we resort to the Bridge design pattern with some additional refinements.

As far as the implementation part is concerned, the bridge wraps a pure abstract class cgalAbstractMeshDomainData which serves as the base class for all the likely implementations of the mesh domain concept.

This abstraction has several pure virtual methods to make the connection between the derived class and the bridge. Implementing all these methods in derived classes is a tedious task. That’s why, an intermediate class based on the CRTP pattern is used to simplify users’ own implementation of the mesh domain. The implementation therefore derived from the CRTP class and not from the abstraction directly.

Of course, it remains to deal with all the mesh domain classes that have been developped by so many people for a long time. The solution that consists in modifying theses classes by adding the CRTP as parent class is clearly unfeasible. Any modification of theses classes cannnot be allowed since it will break the compatibilty with all the existant codes using Cgal. So, one has to resort to composition to circumvent this issu. A wrapper has thus been written, it is templated by the mesh domain it wraps and it inherits from the CRTP class.

Findings

The reasons that drove these developments could seem to be some quite artificial and we agree with that partially. CgalMesh is used by a very large number of people so why would we like to change the way they use it? As said previously, the work we do for the ADT does not target people who are already convinced by CgalMesh but it aims at making it easier to use by phD and post-docs who do not master neither programming nor discrete geometry. Visual programming is a way to make CgalMesh easiest to use. The bridge pattern mixed with CRTP is the solution we propose. We have been using it for 3 months and the bridge was found to be interesting for other problems that remained unfixed until today. Upcoming posts will detail these unexpected additional possibilities.

Cheers !

Thibaud and Côme.

About Thibaud Kloczko

Graduated in CFD, Thibaud Kloczko is a software engineer at Inria. He is involved in the development of the meta platform dtk that aims at speeding up life cycle of business codes into research teams and at sharing software components between teams from different scientific fields (such as medical and biological imaging, numerical simulation, geometry, linear algebra, computational neurology).