An Unstructured Quadrilateral Mesh Example

The CAMAL paver uses the same interface as the CAMAL tri-advance mesher. Example paver1 is similar to trimesh1 except that CMLPaver has replaced CMLTriAdvance as the meshing object.

Another difference is the input data. The input data for the trimesh in Figure 3 has an odd number of points on the boundary loops. This is unaccpetable to the paver unless the mixed-elements flag is set. It is impossible to generate an all quadrilateral mesh with an odd number of points. The total number of points on the boundary must be even for an all quadrilateral mesh.

Also paver1 differs from trimesh1 in another way. It retrieves points and quadrilaterals one buffer at a time. This is helpful with large models when retrieving all of the points and elements might exceed available memory. It is also useful when the generic data types returned are immediately converted to an internal class such as point, node, element, etc. It is not necessary here but illustrates the technique.

    // mesh the surface
  int new_points = 0;
  int num_quads  = 0;
  MySurfEval geom_eval;
  CMLPaver quad_mesher(&geom_eval);
  bool ret_value = quad_mesher.set_boundary_mesh(num_points, points,
                                                 num_loops, loop_sizes, loops);
  if (!ret_value) {
    printf("Failed setting boundary mesh\n");
  }
  

    // delete memory allocated in read_loop_file
  delete [] points;
  delete [] loops;
  delete [] loop_sizes;

In this code fragment, CMLPaver has replace CMLTriAdvance as the meshing object. The code is identical to trimesh1.cpp except for the name of the mesher object.

    // generate the mesh
  if (ret_value) {
    ret_value = quad_mesher.generate_mesh(new_points, num_quads);
    if (!ret_value) {
      printf("Failed generating mesh\n");
    }
  }

    // write output file
  if (ret_value) {
    ret_value = write_quad_file(quad_mesher, new_points, num_quads);
  }

Now writing the mesh file is right after the code to generate the mesh. There is no need to allocate memory to hold the mesh or call CMLPaver::get_mesh() because write_quad_file will retrieve the mesh one buffer at a time.

bool write_quad_file(CMLPaver& quad_mesher, int npoints, int nquads)
{
  FILE* file = fopen("paver1.facet", "w");
  if (file == NULL) {
    printf("Failed to open output file!\n");
    return false;
  }

    // write number of points and number of quadrilaterals
  fprintf(file, "%d %d\n", npoints, nquads);

    // write points (node no., x, y, z)
  int i;
  const int BUF_SIZE = 4096;
  double pbuf[BUF_SIZE];
  int npnts = 0;
  int num = quad_mesher.get_points_buf(BUF_SIZE, pbuf);
  while (num > 0) {
    double* p = pbuf;
    for (i = 0; i < num; i++) {
      fprintf(file, "%d %e %e %e\n", i+1, p[0], p[1], p[2]);
      p += 3;
    }
    npnts += num;
    num = quad_mesher.get_points_buf(BUF_SIZE, pbuf, npnts);
  }
  bool ret_val = npnts == npoints;

After opening an output file and writing the number of points and quadrilaterals to it, a buffer, pbuf, is allocated to hold the points. A call to CMLPaver::get_points_buf() retrieves the first buffer of points. The last argument is the starting index and is optional. It is zero (0) by default. The points returned in the buffer begin at this position. The variable num is the number of points returned. Thus npnts is incremented by num each iteration and is the starting position for the next call to CMLPaver::get_points_buf. There are no more points when CMLPaver::get_points_buf() returns zero (0).

    // write quadrilaterals (quad no., n1, n2, n3, n4)
  int nqds = 0;
  if (ret_val) {
    int qbuf[BUF_SIZE];
    num = quad_mesher.get_quads_buf(BUF_SIZE, qbuf);
    while (num > 0) {
      int* q = qbuf;
      for (i = 0; i < num; i++) {
        fprintf(file, "%d %d %d %d %d\n", i+1, q[0]+1, q[1]+1, q[2]+1, q[3]+1);
        q += 4;
      }
      nqds += num;
      num = quad_mesher.get_quads_buf(BUF_SIZE, qbuf, nqds);
    }
    ret_val = nqds == nquads;

Likewise, a buffer, qbuf, is allocated to hold the quadrilaterals. Each call to CMLPaver::get_quads_buf() returns at most BUF_SIZE/4 elements.

Figure 5 shows the unstructured quadrilateral mesh for the surface in Figure 3.

pavemesh.png

Figure 5: Paved (Quadrilateral) Mesh Example

Other Examples

  1. A Simple Tetrahedral Mesh Example
  2. A Triangle Mesh Example
  3. A Swept Hexahedral Mesh Example
  4. Curve Meshing Examples
  5. Another Triangle Mesh Example
  6. A Structured Quadrilateral Mesh Example -- Surface Mapper
  7. A Structured Quadrilateral Mesh Example -- Surface Submapper
  8. A Structured Hexahedral Mesh Example -- Volume Mapper

CAMAL 5.2-0 documentation created on 1 Jun 2010
Comments to csimsoft.com