sandbox/aberny/output_stl.h

    STL output

    This function output a scalar field into an stl file by using the facets algoritm. The function write the data into a binary file so that the resuting STL file can be read by any stl-reader (such as meshlab for example).

    The input parameters are a volume fraction field c and an optional file name. By default the name will be “out.stl”

    This output works in serial, with openmp and with MPI

    #if dimension >=3
    #include "fractions.h"
    
    struct stlOutput{
      scalar c;
      char * name; // optional
    };
    
    trace
    void stl_output_binary (struct stlOutput p)
    {
      bool name = false;
      scalar c = p.c;
      if (!p.name) {
        p.name = malloc(80);
        strcpy( p.name, "out.stl");
        name = true;
      }

    For the MPI output, we open as many file as there is process. We will use a cat command at the end and then delete those external file

      @if _MPI
      char outMPI[80];
      sprintf(outMPI, "_outSTL-%d.stl", pid() );
      FILE * fp = fopen(outMPI, "wb");
      @else
      FILE * fp = fopen(p.name, "wb");
      @endif

    We write the data into a binary file. The header contains a string of 80 chars that does not start with “solid”. We put an empty one.

      char title_string[80];
      face vector s;
      s.x.i = -1;
      int nfacets = 0;
    
    @if _MPI
      if (pid()==0){ //Write in the 0 file
    @endif
      fwrite( title_string, 1, sizeof(title_string), fp); //Title
      fwrite( &nfacets, sizeof(int), 1, fp); //Number of facets - we will update this later
    @if _MPI
      }
    @endif
      foreach(reduction(+:nfacets)){
        if (c[] > 1e-6 && c[] < 1. - 1e-6) {
          coord n = facet_normal (point, c, s);
          double alpha = plane_alpha (c[], n);
          coord v[12];
          int m = facets (n, alpha, v, 1.); //m is the number of coordinates
          //Assume all values in v belong to the same plane.
          for (int j = 0; j < m - 2; j++){

    In an STL file, there is first the normal of a surface, then the cordinate of the triangle and then a short int equal to 0

            float word[12] = { n.x, n.y, n.z,
               x + v[0].x*Delta, y + v[0].y*Delta, z + v[0].z*Delta, 
               x + v[j+1].x*Delta, y + v[j+1].y*Delta, z + v[j+1].z*Delta, 
               x + v[j+2].x*Delta, y + v[j+2].y*Delta, z + v[j+2].z*Delta};
            unsigned short *trmpt = (unsigned short*)(&(word[12]) + 1);
            *trmpt = 0;
            fwrite(word, 12*sizeof(float) + sizeof(unsigned short), 1, fp);      
        nfacets += 1;
      } 
        }
        }
    @if _MPI
      if (pid() == 0)
        {
    @endif
          // fprintf(stderr, "nfacets=%d\n", nfacets);
          // fprintf(stderr, "Rewriting headers...\n");

    Update the number of facetes at the top of the file

          fseek(fp, 80, SEEK_SET);
          fwrite( &nfacets, sizeof(int), 1, fp);
    @if _MPI
        }
        fclose(fp);

    Concatenate all the file into a single file

        char copyCat[99];
        sprintf(copyCat, "cat _outSTL-*.stl > %s", p.name);
        if (pid() == 0){
          system(copyCat);
          system("rm -f _outSTL-*.stl");
        }
    @else

    Don’t forget to close the file

        fclose(fp);
    @endif
      if (name)
        free(p.name);
    }
    #endif

    An example using this output function can be found here: csgBool.c

    The stl file can be open with meshlab, for example.