This page describes how to setup and run the MeshGenC++ mesh generator for a particular 2D example. If you encounter any difficulties, please send e-mail to the discussion group.

Example details

In this example we will use MeshGenC++ to generate a mesh for the domain that is made of up of the intersection of the interior of a square and the exterior of two circles and two ellipses (see images below).

_images/tutorial_face.jpg _images/tutorial_face_filled.jpg

In order to generate such a mesh we will need three essential pieces:

  • An input file that contains basic information about the mesh we wish to generate.
  • A function that returns the signed distance from any point to the boundary of the domain (in reality we only need an approximate signed distance function -- i.e., a properly normalized level set function).
  • A function that returns at every point in the domain a desired grid spacing value.

In the description below we go step-by-step through the process of generating the mesh.


First we will need to create a directory to house our example. Do this as follows:

$ cd $MESHGENCPP/apps/2d
$ mkdir myexample
$ cd myexample


Next we need to create a Makefile (the name of this file is Makefile). The basic MeshGenC++ makefile is of the following form:

#       MeshGenC++ Makefile
#       To make an executable, type: make
#       (from the application sub-directory)

### definitions ###

# default/library definitions
include $(MESHGENCPP)/lib/2d/Makefile.defs

# compiler options
#FFLAGS =  -c -O4
#LINK    = g++

# overridden library objects
#MeshPreProcess   = MeshPreProcess
#MeshPostProcess1 = MeshPostProcess1
#MeshPostProcess2 = MeshPostProcess2

# place to add object modules

### targets ###

.cpp.o: ; $(LINK) $(FFLAGS) $*.cpp -o $*.o

mesh.exe: $(ALL_OBJECTS)
        $(LINK) $(LFLAGS) $(ALL_OBJECTS) -o mesh.exe

include $(MESHGENCPP)/lib/2d/Makefile.targets

### DO NOT remove this line - make depends on it ###


Next we need to create the file main.cpp. The basic MeshGenC++ main.cpp file is of the following form:

#include <cstdlib>
#include <iostream>
#include <iomanip>
#include "meshdefs.h"

// ==============================================================================
//  Copyright J.A. Rossmanith and the DoGPack Team
//  This software is made available for research and instructional use only.
//  You may copy and use this software without charge for these non-commercial
//  purposes, provided that the copyright notice and associated text is
//  reproduced on all copies.  For all other uses (including distribution of
//  modified versions), please contact the author at the address given below.
//  *** This software is made available "as is" without any assurance that it
//  *** will work for your purposes.  The software may in fact have defects, so
//  *** use the software at your own risk.
// ==============================================================================

int main(int argc, char* argv[])
    // NOTE: You should not have to modify this part of the code.
    //       To change parameters, modify the following files:
    //            1. input2D.data
    //            2. SignedDistance.cpp
    //            3. GridSpacing.cpp

    // Get current time
    double time1 = time(NULL);

    // Call the mesh generator
    int meshgen2D(int argc,char**argv);
    int m = meshgen2D(argc, argv);

    // Get current time
    double time2 = time(NULL);

    // Output elapsed time
    cout << setprecision(5);
    cout << " Total elapsed time in seconds = " << setw(11)
            << scientific << time2-time1 << endl << endl;

    return m;


Next we need to create and edit the input file (input.data). In particular, we need specify the following pieces of information:

  • Initial grid spacing (H0): this will control the initial spacing of triangles. The number of elements that are created in this initial triangulation is the maximum number of elements during the entire mesh generation process.
  • Bounding box (xmin, xmax, ymin, ymax): a box that encloses the entire region that will be triangulated.
  • Number of fixed points: sets the number of points that will never get deleted or moved during the mesh generation process.
  • Fixed points (x, y): List of x and y coordinates of all the points that will never get deleted or moved during the mesh generation process.

The final input.data will be of the following form:

Unstructured          : Grid type (Structured vs. Unstructured)
0.02                  : Initial grid spacing (H0)
50000                 : Maximum allowed iterations
Bounding box:
-1.0e0                : xmin
 1.0e0                : xmax
-1.0e0                : ymin
 1.0e0                : ymax
4                    : Number of fixed points
Fixed points (x y):
-1.000000000000000e+00    -1.000000000000000e+00
-1.000000000000000e+00     1.000000000000000e+00
 1.000000000000000e+00    -1.000000000000000e+00
 1.000000000000000e+00     1.000000000000000e+00


Next we will need to create a signed distance function to the boundary of the domain that we wish to mesh. This function takes as input a point and returns one the following three possibilities:

  • If the point is interior to the domain, the signed distance function returns -1 times the distance to the closest point on the domain boundary.
  • If the point is exterior to the domain, the signed distance function returns the distance to the closest point on the domain boundary.
  • If the point is on the domain boundary, the signed distance function returns zero.

In practice it is generally quite difficult to create a mathematically rigorous signed distance function for a particular domain. For the purposes of the mesh generator, we only really need a level set function that is approximately a signed distance function. This is because the only place in the MeshGenC++ code that makes use of the distance part of the signed distance function is in the projection of points from the exterior of the domain back onto the domain boundary -- this projection is typically done on points that are already very close to the boundary.

For the current example, we use the following level set function. It is not a rigorous signed distance function, but it is easy to create, and works very well in practice.

#include "meshdefs.h"

//  Signed distance function:
//      SignedDistance(x,y) < 0 inside the region
//      SignedDistance(x,y) = 0 on the boundary
//      SignedDistance(x,y) > 0 outside of the region
double SignedDistance(point pt)
  double Min(double,double);
  double x = pt.x;
  double y = pt.y;

  double out1 =  (x+1.0);
  double out2 = -(x-1.0);
  double out3 =  (y+1.0);
  double out4 = -(y-1.0);
  double lft_eye = sqrt(pow(x+0.5,2) + pow(y-0.5,2)) - 0.25;
  double rgt_eye = sqrt(pow(x-0.5,2) + pow(y-0.5,2)) - 0.25;
  double mouth = sqrt(pow(x,2) + 10.0*pow(y+0.5,2)) - 0.75;
  double nose = sqrt(3.0*pow(x,2) + pow(y-0.1,2)) - 0.15;

  double dist = -Min(Min(Min(Min(out1,out2),

  return dist;


The function GridSpacing.cpp controls the relative spacing of elements in the mesh. If this function returns a constant, then the mesh generator will attempt to create a mesh with spacing that is roughly uniform.

In this example, we will pick a spacing that concentrates more points near the boundaries and less in the interior regions. We can use the already existing SignedDistance.cpp function to help us out. In particular, we use the following file:

#include "meshdefs.h"

//  Grid spacing function:
//     This functions sets a relative grid spacing of points
//     The input is a point (i.e., x and y coordinate), and the
//     output is a real positive number called "hdist". Large (small)
//     "hdist" means relatively large (small) grid spacing (relative to
//     the maximum and minimum values of GridSpacing.cpp).
//     For example, GridSpacing = 1   for all input x and y and
//                  GridSpacing = 55  for all input x and y
//           will produce the same nearly uniform mesh since
//           the relative variation of GridSpacing in both
//           examples is zero.
double GridSpacing(point pt)
  double Min(double,double);
  double xin = pt.x;
  double yin = pt.y;

  double SignedDistance(point pt);
  double dist = SignedDistance(pt);

  double hdist = 0.2e0 - dist;

  return hdist;


In order to compile this example simply type:

$ make

Once compiled, execute the code by typing:

$ mesh.exe

During the running of the program you will see printed to the screen the iteration count, as well as statements that show whenever a new triangulation is computed. After successful completion of the code, a statement similar to the following is produced:

         Number of Elements:      8206
Number of Physical Elements:      7455
   Number of Ghost Elements:       751
            Number of Nodes:      4851
   Number of Physical Nodes:      4100
   Number of Boundary Nodes:       751
            Number of Edges:     11558

       Total Area Covered:    3.0071970517733870e+00
  Area Ratio: small/large:    7.8272678749387078e-02
 Angle Ratio: minAngle/60:    5.8289165748986904e-01

Total elapsed time in seconds = 1.50000e+01


If MATLAB is installed, the resulting mesh can be visualized by executing the following script within a MATLAB command window:

>> plotmesh2


Before executing this command, first open MATLAB, then change directory to the $MESHGENCPP/apps/2d/myexample directory in the MATLAB command window.

This should result in the following two plots being produced:

_images/tutorial_2d_face_matlab1.jpg _images/tutorial_2d_face_matlab2.jpg

Otherwise, if matplotlib is installed, the resulting mesh can be visualized by executing the following python script:

$ python $MESHGENCPP/viz/python/plotmesh2.py

or using the following shortcut (this shortcut is defined in setenv.bash and setenv.csh files):

$ plotmesh2

This should result in the following two plots being produced:

_images/tutorial_2d_face_python1.jpg _images/tutorial_2d_face_python2.jpg