#include <extUtil.h>
#include <time.h>

#define MAX_NODE_NR  2100000000
#define TEST 0

/*******************************************************************/
/* selectDisplayFaces  vom 16.3.1997 Philipp                       */
/*                          1.12.1997 Wittig                       */
/*                         11.10.1999 Wittig                       */
/*                         14.11.2000 Wittig                       */
/*                         14.04.2003 Wittig                       */
/* in:                                                             */
/*    elements *elems zb. aus frd-file   (HEXA8!)                  */
/*    int numElems    anzahl der elemente                          */
/*    int numEdges    anzahl der Kanten (node1, node2)             */
/*    int Rückgabewert    anzahl der freien faces                  */
/*    int *pfaces     Startaddresse eines Speicherbereiches der    */
/*                    mit oberflaechen beschrieben wird            */
/*                    (n1,n2,n3,<n4|side.nr>,elem-index -          */
/*                     die ersten 3 n werden aufsteigend sortiert  */
/*                     abgelegt, der 4.n wird dann mit der seiten- */
/*                     nr überschrieben                            */
/*    Dieses Feld wird anschliessend nach n1 sortiert, alle doppel-*/
/*    ten surfs stehen hintereinander.                             */
/*    Anschliessend wird dieser Speicherbereich traversiert und    */
/*    alle nicht doppelt vorkommenden surfs werden in den selben   */
/*    speicherbereich geschrieben, der inhalt wird überschrieben.  */
/*                                                                 */
/*******************************************************************/

int selectDisplayFacesHe8 (Elements *elems, int numElems, int **ptr, int *edges) {
  /* wählt äußere Elementflächen aus, alle doppelt vorkommenden Flächen
     werden eliminiert
     Freie Elementkanten werden gesucht.  */

  int numFaces, numDisplayFaces=0, i ;
  int numEdges=0;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax, *pmaxd ;
  clock_t t0, t1, t2 ;
  double deltaT ;
/*  extern int compareFaces (int *, int *) ;   */
  extern int compareFaces () ;
  extern int compareElnum () ;
  extern void vdsort ( int *) ;
  extern int commonEdge (int *, int *) ;

  t0=clock() ;

  numFaces = 6 * numElems ;
  size = (6* numFaces+12*6*numElems) * sizeof(int) ;
   printf("numFaces:%d numElems:%d size:%d\n",numFaces,numElems,size);
  if ( size < 1920 ) size = 1920;

  if ( (pfaces = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }

  pCurrentFace = pfaces ;

  for ( i = 0; i < numElems; i++ ) {
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[3] ;
    *(pCurrentFace+2) = elems[i].nod[2] ;
    *(pCurrentFace+3) = elems[i].nod[1] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 1 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[4] ;
    *(pCurrentFace+1) = elems[i].nod[5] ;
    *(pCurrentFace+2) = elems[i].nod[6] ;
    *(pCurrentFace+3) = elems[i].nod[7] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 2 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[1] ;
    *(pCurrentFace+2) = elems[i].nod[5] ;
    *(pCurrentFace+3) = elems[i].nod[4] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 3 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[1] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[6] ;
    *(pCurrentFace+3) = elems[i].nod[5] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 4 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[3] ;
    *(pCurrentFace+1) = elems[i].nod[7] ;
    *(pCurrentFace+2) = elems[i].nod[6] ;
    *(pCurrentFace+3) = elems[i].nod[2] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 5 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[4] ;
    *(pCurrentFace+2) = elems[i].nod[7] ;
    *(pCurrentFace+3) = elems[i].nod[3] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 6 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
  }
  pmax = pCurrentFace -6 ;  /* größter zulässiger Face-Pointer */

  /* nach Knotennummern sortieren */
  qsort (pfaces, numFaces, 6*sizeof(int), compareFaces) ;

  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 6 ;
              /* <= pmax, damit die letzte Fläche nicht verloren geht */
  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
    if ( compareFaces (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 12 ;
      pFaceN1 += 12 ; }
    else {
      i = *(pFaceN+4) ;
      switch ( *(pFaceN + 3) ) {
        case 1:
          *pCurrentFace = elems[i].nod[0] ;          /* Feld wird gleichzeitig abgefragt (pFaceN) */
          *(pCurrentFace+1) = elems[i].nod[3] ;      /* und neu beschrieben (pCurrentFace) */
          *(pCurrentFace+2) = elems[i].nod[2] ;
          *(pCurrentFace+3) = elems[i].nod[1] ;
          break;
        case 2:
          *pCurrentFace = elems[i].nod[4] ;
          *(pCurrentFace+1) = elems[i].nod[5] ;
          *(pCurrentFace+2) = elems[i].nod[6] ;
          *(pCurrentFace+3) = elems[i].nod[7] ;
          break;
        case 3:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[1] ;
          *(pCurrentFace+2) = elems[i].nod[5] ;
          *(pCurrentFace+3) = elems[i].nod[4] ;
          break;
        case 4:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[6] ;
          *(pCurrentFace+3) = elems[i].nod[5] ;
          break;
        case 5:
          *pCurrentFace = elems[i].nod[3] ;
          *(pCurrentFace+1) = elems[i].nod[7] ;
          *(pCurrentFace+2) = elems[i].nod[6] ;
          *(pCurrentFace+3) = elems[i].nod[2] ;
          break;
        case 6:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[4] ;
          *(pCurrentFace+2) = elems[i].nod[7] ;
          *(pCurrentFace+3) = elems[i].nod[3] ;
          break;
      }
      *(pCurrentFace+4) = elems[i].nr ;
      *(pCurrentFace+5) = elems[i].group ;
      pFaceN += 6 ;
      pFaceN1 += 6 ;
      pCurrentFace += 6 ;
      numDisplayFaces += 1 ;
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 12 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }
  pmaxd = pCurrentFace -6 ;  /* größter zulässiger DisplayFace-Pointer */

#if TEST
  t1=clock() ;
  deltaT = ((double)t1 - (double)t0)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesHe8: %i faces reduced to %i in %.2f seconds\n",
      numFaces, numDisplayFaces, deltaT) ;
#endif

  /* Suche freie Kanten des Modells */
  /* wenn 2 aufeinander folgende Flaechen zu einem Element gehoeren, ist eine Kante gefunden */

  /* nach Elementnummern sortieren */
  qsort (pfaces, numDisplayFaces, 6*sizeof(int), compareElnum) ;

  pFaceN = pfaces ;
  pFaceN1 = pfaces + 6 ;

  while ( pFaceN < pmaxd )    /* bis zur vorletzten Fläche */
  {
    if ( *(pFaceN+4) == *(pFaceN1+4) )  /* sind beide Flaechen vom gleichen Element? */
    {
      if ( (i=commonEdge (pFaceN, pFaceN1)) != -1 )
      {
        *pCurrentFace = *(pFaceN+i);
        if ( i == 3 ) i = -1;
        *(pCurrentFace+1) = *(pFaceN+i+1);
        pCurrentFace += 2;              /* Knotenpaare fortlaufend hinter Flächen speichern */
        numEdges++;
      }
      pFaceN1 += 6 ;                            /* alle Flächen eines Elements abfragen  */
      if ( pFaceN1 > pmaxd ) /* Überlauf abfangen */
      {
        pFaceN += 6 ;
        pFaceN1 = pFaceN + 6 ;
      }
    }
    else
    {
      pFaceN += 6 ;
      pFaceN1 = pFaceN + 6 ;
    }
  }

#if TEST
  t2=clock() ;
  deltaT = ((double)t2 - (double)t1)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFaces: %i free edges detected in %.2f seconds\n",
      numEdges, deltaT) ;
#endif

  *ptr=pfaces;
  *edges=numEdges;

  return numDisplayFaces ;
}



int selectDisplayFacesPe6 (Elements *elems, int numElems, int **ptr, int *edges) {
  /* wählt äußere Elementflächen aus, alle doppelt vorkommenden Flächen
     werden eliminiert
     Freie Elementkanten werden gesucht.  */


  int numFaces, numDisplayFaces=0, i ;
  int numEdges=0;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax, *pmaxd ;
  clock_t t0, t1, t2 ;
  double deltaT ;
/*  extern int compareFaces (int *, int *) ;   */
  extern int compareFaces () ;
  extern int compareElnum () ;
  extern void vdsort ( int *) ;
  extern int commonEdge (int *, int *) ;

  t0=clock() ;

  numFaces = 5 * numElems ;
  size = (5* numFaces+12*5*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;

  if ( (pfaces = (int *)malloc( size )) == NULL )
  { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }

  pCurrentFace = pfaces ;

  for ( i = 0; i < numElems; i++ ) {
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[1] ;
    *(pCurrentFace+3) = elems[i].nod[1] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 1 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[1] ;
    *(pCurrentFace+2) = elems[i].nod[4] ;
    *(pCurrentFace+3) = elems[i].nod[3] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 2 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[1] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[5] ;
    *(pCurrentFace+3) = elems[i].nod[4] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 3 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[2] ;
    *(pCurrentFace+1) = elems[i].nod[0] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = elems[i].nod[5] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 4 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[5] ;
    *(pCurrentFace+1) = elems[i].nod[3] ;
    *(pCurrentFace+2) = elems[i].nod[4] ;
    *(pCurrentFace+3) = elems[i].nod[4] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 5 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
  }
  pmax = pCurrentFace -6 ;  /* größter zulässiger Face-Pointer */

  /* nach Knotennummern sortieren */
  qsort (pfaces, numFaces, 6*sizeof(int), compareFaces) ;

  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 6 ;
              /* <= pmax, damit die letzte Fläche nicht verloren geht */
  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
    if ( compareFaces (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 12 ;
      pFaceN1 += 12 ; }
    else {
      i = *(pFaceN+4) ;
      switch ( *(pFaceN + 3) ) {
        case 1:
          *pCurrentFace = elems[i].nod[0] ;          /* Feld wird gleichzeitig abgefragt (pFaceN) */
          *(pCurrentFace+1) = elems[i].nod[2] ;      /* und neu beschrieben (pCurrentFace) */
          *(pCurrentFace+2) = elems[i].nod[1] ;
          *(pCurrentFace+3) = elems[i].nod[1] ;
          break;
        case 2:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[1] ;
          *(pCurrentFace+2) = elems[i].nod[4] ;
          *(pCurrentFace+3) = elems[i].nod[3] ;
          break;
        case 3:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[5] ;
          *(pCurrentFace+3) = elems[i].nod[4] ;
          break;
        case 4:
          *pCurrentFace = elems[i].nod[2] ;
          *(pCurrentFace+1) = elems[i].nod[0] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[5] ;
          break;
        case 5:
          *pCurrentFace = elems[i].nod[5] ;
          *(pCurrentFace+1) = elems[i].nod[3] ;
          *(pCurrentFace+2) = elems[i].nod[4] ;
          *(pCurrentFace+3) = elems[i].nod[4] ;
          break;
      }
      *(pCurrentFace+4) = elems[i].nr ;
      *(pCurrentFace+5) = elems[i].group ;
      pFaceN += 6 ;
      pFaceN1 += 6 ;
      pCurrentFace += 6 ;
      numDisplayFaces += 1 ;
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 12 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }
  pmaxd = pCurrentFace -6 ;  /* größter zulässiger DisplayFace-Pointer */

#if TEST
  t1=clock() ;
  deltaT = ((double)t1 - (double)t0)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesHe8: %i faces reduced to %i in %.2f seconds\n",
      numFaces, numDisplayFaces, deltaT) ;
#endif

  /* Suche freie Kanten des Modells */
  /* wenn 2 aufeinander folgende Flaechen zu einem Element gehoeren, ist eine Kante gefunden */

  /* nach Elementnummern sortieren */
  qsort (pfaces, numDisplayFaces, 6*sizeof(int), compareElnum) ;

  pFaceN = pfaces ;
  pFaceN1 = pfaces + 6 ;

  while ( pFaceN < pmaxd )    /* bis zur vorletzten Fläche */
  {
    if ( *(pFaceN+4) == *(pFaceN1+4) )  /* sind beide Flaechen vom gleichen Element? */
    {
      if ( (i=commonEdge (pFaceN, pFaceN1)) != -1 )
      {
        *pCurrentFace = *(pFaceN+i);
        if ( i == 3 ) i = -1;
        *(pCurrentFace+1) = *(pFaceN+i+1);
        pCurrentFace += 2;              /* Knotenpaare fortlaufend hinter Flächen speichern */
        numEdges++;
      }
      pFaceN1 += 6 ;                            /* alle Flächen eines Elements abfragen  */
      if ( pFaceN1 > pmaxd ) /* Überlauf abfangen */
      {
        pFaceN += 6 ;
        pFaceN1 = pFaceN + 6 ;
      }
    }
    else
    {
      pFaceN += 6 ;
      pFaceN1 = pFaceN + 6 ;
    }
  }

#if TEST
  t2=clock() ;
  deltaT = ((double)t2 - (double)t1)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFaces: %i free edges detected in %.2f seconds\n",
      numEdges, deltaT) ;
#endif

  *ptr=pfaces;
  *edges=numEdges;

  return numDisplayFaces ;
}




int selectDisplayFacesHe20(Elements *elems, int numElems, int **ptr, int *edges) {
  /* waehlt Elementflaechen aus, alle doppelt vorkommenden Flaechen werden eliminiert.
     Freie Elementkanten werden gesucht.  */

  /* erweiterung fuer He26 */
  int numDispFaces=0;
  int *pDispFace;
  int *pDispFaceStart;
  /* ende */

  int numFaces, numDisplayFaces=0, i ;
  int numEdges=0;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax, *pmaxd ;
  clock_t t0, t1, t2 ;
  double deltaT ;
  extern int compareFaces () ;
  extern int compareElnum () ;
  extern void vdsort ( int *) ;
  extern int commonEdge (int *, int *) ;


  t0=clock() ;

  numFaces = 6 * numElems ;

  size = (10* numFaces+24*6*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pfaces = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }


  pCurrentFace = pfaces ;

  /* use midside-nodes for surface extraction */
  for ( i = 0; i < numElems; i++ ) {
    *pCurrentFace = elems[i].nod[8] ;
    *(pCurrentFace+1) = elems[i].nod[11] ;
    *(pCurrentFace+2) = elems[i].nod[10] ;
    *(pCurrentFace+3) = elems[i].nod[9] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 1 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[8] ;
    *(pCurrentFace+1) = elems[i].nod[13] ;
    *(pCurrentFace+2) = elems[i].nod[16] ;
    *(pCurrentFace+3) = elems[i].nod[12] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 2 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[9] ;
    *(pCurrentFace+1) = elems[i].nod[14] ;
    *(pCurrentFace+2) = elems[i].nod[17] ;
    *(pCurrentFace+3) = elems[i].nod[13] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 3 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[10] ;
    *(pCurrentFace+1) = elems[i].nod[14] ;
    *(pCurrentFace+2) = elems[i].nod[18] ;
    *(pCurrentFace+3) = elems[i].nod[15] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 4 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[11] ;
    *(pCurrentFace+1) = elems[i].nod[12] ;
    *(pCurrentFace+2) = elems[i].nod[19] ;
    *(pCurrentFace+3) = elems[i].nod[15] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 5 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[16] ;
    *(pCurrentFace+1) = elems[i].nod[17] ;
    *(pCurrentFace+2) = elems[i].nod[18] ;
    *(pCurrentFace+3) = elems[i].nod[19] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 6 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
  }
  pmax = pCurrentFace -10 ;  /* größter zulässiger Face-Pointer */

  /* nach Knotennummern sortieren */
  qsort (pfaces, numFaces, 10*sizeof(int), compareFaces) ;

  /* erweiterung fuer He26-Triangles */
  size = (26* numFaces+24*6*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pDispFace = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pDispFace\n\n") ; exit(-1); }
  pDispFaceStart=pDispFace;
  /* ende */

  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 10 ;
              /* <= pmax, damit die letzte Fläche nicht verloren geht */
  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
    if ( compareFaces (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 20 ;
      pFaceN1 += 20 ; }
    else {
      i = *(pFaceN+4) ;
      switch ( *(pFaceN + 3) ) {
        case 1:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[3] ;
          *(pCurrentFace+2) = elems[i].nod[2] ;
          *(pCurrentFace+3) = elems[i].nod[1] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[11] ;
          *(pCurrentFace+7) = elems[i].nod[10] ;
          *(pCurrentFace+8) = elems[i].nod[9] ;
          *(pCurrentFace+9) = elems[i].nod[8] ;

  /* es folgen die Dreiecke fuer die Surfaces */
          *pDispFace     = elems[i].nod[3];
          *(pDispFace+1)    = elems[i].nod[10];
          *(pDispFace+2)    = elems[i].nod[11];
          *(pDispFace+3) = elems[i].nod[10];
          *(pDispFace+4)    = elems[i].nod[24];
          *(pDispFace+5)    = elems[i].nod[11];
          *(pDispFace+6) = elems[i].nod[11];
          *(pDispFace+7)    = elems[i].nod[24];
          *(pDispFace+8)    = elems[i].nod[ 0];
          *(pDispFace+9) = elems[i].nod[24];
          *(pDispFace+10)   = elems[i].nod[ 8];
          *(pDispFace+11)   = elems[i].nod[ 0];

          *(pDispFace+12)= elems[i].nod[10];
          *(pDispFace+13)   = elems[i].nod[ 2];
          *(pDispFace+14)   = elems[i].nod[24];
          *(pDispFace+15)= elems[i].nod[ 2];
          *(pDispFace+16)   = elems[i].nod[ 9];
          *(pDispFace+17)   = elems[i].nod[24];
          *(pDispFace+18)= elems[i].nod[24];
          *(pDispFace+19)   = elems[i].nod[ 9];
          *(pDispFace+20)   = elems[i].nod[ 8];
          *(pDispFace+21)= elems[i].nod[ 9];
          *(pDispFace+22)   = elems[i].nod[ 1];
          *(pDispFace+23)   = elems[i].nod[ 8];
  /* ende */
          break;
        case 2:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[1] ;
          *(pCurrentFace+2) = elems[i].nod[5] ;
          *(pCurrentFace+3) = elems[i].nod[4] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[ 8] ;
          *(pCurrentFace+7) = elems[i].nod[13] ;
          *(pCurrentFace+8) = elems[i].nod[16] ;
          *(pCurrentFace+9) = elems[i].nod[12] ;

          *pDispFace     = elems[i].nod[0];
          *(pDispFace+1)    = elems[i].nod[ 8];
          *(pDispFace+2)    = elems[i].nod[12];
          *(pDispFace+3) = elems[i].nod[ 8];
          *(pDispFace+4)    = elems[i].nod[20];
          *(pDispFace+5)    = elems[i].nod[12];
          *(pDispFace+6) = elems[i].nod[12];
          *(pDispFace+7)    = elems[i].nod[20];
          *(pDispFace+8)    = elems[i].nod[ 4];
          *(pDispFace+9) = elems[i].nod[20];
          *(pDispFace+10)   = elems[i].nod[16];
          *(pDispFace+11)   = elems[i].nod[ 4];

          *(pDispFace+12)= elems[i].nod[ 8];
          *(pDispFace+13)   = elems[i].nod[ 1];
          *(pDispFace+14)   = elems[i].nod[20];
          *(pDispFace+15)= elems[i].nod[ 1];
          *(pDispFace+16)   = elems[i].nod[13];
          *(pDispFace+17)   = elems[i].nod[20];
          *(pDispFace+18)= elems[i].nod[20];
          *(pDispFace+19)   = elems[i].nod[13];
          *(pDispFace+20)   = elems[i].nod[16];
          *(pDispFace+21)= elems[i].nod[13];
          *(pDispFace+22)   = elems[i].nod[ 5];
          *(pDispFace+23)   = elems[i].nod[16];
   /* ende */
          break;
        case 3:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[6] ;
          *(pCurrentFace+3) = elems[i].nod[5] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[ 9] ;
          *(pCurrentFace+7) = elems[i].nod[14] ;
          *(pCurrentFace+8) = elems[i].nod[17] ;
          *(pCurrentFace+9) = elems[i].nod[13] ;

          *pDispFace     = elems[i].nod[1];
          *(pDispFace+1)    = elems[i].nod[ 9];
          *(pDispFace+2)    = elems[i].nod[13];
          *(pDispFace+3) = elems[i].nod[ 9];
          *(pDispFace+4)    = elems[i].nod[21];
          *(pDispFace+5)    = elems[i].nod[13];
          *(pDispFace+6) = elems[i].nod[13];
          *(pDispFace+7)    = elems[i].nod[21];
          *(pDispFace+8)    = elems[i].nod[ 5];
          *(pDispFace+9) = elems[i].nod[21];
          *(pDispFace+10)   = elems[i].nod[17];
          *(pDispFace+11)   = elems[i].nod[ 5];

          *(pDispFace+12)= elems[i].nod[ 9];
          *(pDispFace+13)   = elems[i].nod[ 2];
          *(pDispFace+14)   = elems[i].nod[21];
          *(pDispFace+15)= elems[i].nod[ 2];
          *(pDispFace+16)   = elems[i].nod[14];
          *(pDispFace+17)   = elems[i].nod[21];
          *(pDispFace+18)= elems[i].nod[21];
          *(pDispFace+19)   = elems[i].nod[14];
          *(pDispFace+20)   = elems[i].nod[17];
          *(pDispFace+21)= elems[i].nod[14];
          *(pDispFace+22)   = elems[i].nod[ 6];
          *(pDispFace+23)   = elems[i].nod[17];
 /* ende */
          break;
        case 4:
          *pCurrentFace = elems[i].nod[2] ;
          *(pCurrentFace+1) = elems[i].nod[3] ;
          *(pCurrentFace+2) = elems[i].nod[7] ;
          *(pCurrentFace+3) = elems[i].nod[6] ;
   /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[10] ;
          *(pCurrentFace+7) = elems[i].nod[15] ;
          *(pCurrentFace+8) = elems[i].nod[18] ;
          *(pCurrentFace+9) = elems[i].nod[14] ;

          *pDispFace     = elems[i].nod[2];
          *(pDispFace+1)    = elems[i].nod[10];
          *(pDispFace+2)    = elems[i].nod[14];
          *(pDispFace+3) = elems[i].nod[10];
          *(pDispFace+4)    = elems[i].nod[22];
          *(pDispFace+5)    = elems[i].nod[14];
          *(pDispFace+6) = elems[i].nod[14];
          *(pDispFace+7)    = elems[i].nod[22];
          *(pDispFace+8)    = elems[i].nod[ 6];
          *(pDispFace+9) = elems[i].nod[22];
          *(pDispFace+10)   = elems[i].nod[18];
          *(pDispFace+11)   = elems[i].nod[ 6];

          *(pDispFace+12)= elems[i].nod[10];
          *(pDispFace+13)   = elems[i].nod[ 3];
          *(pDispFace+14)   = elems[i].nod[22];
          *(pDispFace+15)= elems[i].nod[ 3];
          *(pDispFace+16)   = elems[i].nod[15];
          *(pDispFace+17)   = elems[i].nod[22];
          *(pDispFace+18)= elems[i].nod[22];
          *(pDispFace+19)   = elems[i].nod[15];
          *(pDispFace+20)   = elems[i].nod[18];
          *(pDispFace+21)= elems[i].nod[15];
          *(pDispFace+22)   = elems[i].nod[ 7];
          *(pDispFace+23)   = elems[i].nod[18];
  /* ende */
         break;
        case 5:
          *pCurrentFace = elems[i].nod[3] ;
          *(pCurrentFace+1) = elems[i].nod[0] ;
          *(pCurrentFace+2) = elems[i].nod[4] ;
          *(pCurrentFace+3) = elems[i].nod[7] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[11] ;
          *(pCurrentFace+7) = elems[i].nod[12] ;
          *(pCurrentFace+8) = elems[i].nod[19] ;
          *(pCurrentFace+9) = elems[i].nod[15] ;

          *pDispFace     = elems[i].nod[3];
          *(pDispFace+1)    = elems[i].nod[11];
          *(pDispFace+2)    = elems[i].nod[15];
          *(pDispFace+3) = elems[i].nod[11];
          *(pDispFace+4)    = elems[i].nod[23];
          *(pDispFace+5)    = elems[i].nod[15];
          *(pDispFace+6) = elems[i].nod[15];
          *(pDispFace+7)    = elems[i].nod[23];
          *(pDispFace+8)    = elems[i].nod[ 7];
          *(pDispFace+9) = elems[i].nod[23];
          *(pDispFace+10)   = elems[i].nod[19];
          *(pDispFace+11)   = elems[i].nod[ 7];

          *(pDispFace+12)= elems[i].nod[11];
          *(pDispFace+13)   = elems[i].nod[ 0];
          *(pDispFace+14)   = elems[i].nod[23];
          *(pDispFace+15)= elems[i].nod[ 0];
          *(pDispFace+16)   = elems[i].nod[12];
          *(pDispFace+17)   = elems[i].nod[23];
          *(pDispFace+18)= elems[i].nod[23];
          *(pDispFace+19)   = elems[i].nod[12];
          *(pDispFace+20)   = elems[i].nod[19];
          *(pDispFace+21)= elems[i].nod[12];
          *(pDispFace+22)   = elems[i].nod[ 4];
          *(pDispFace+23)   = elems[i].nod[19];
  /* ende */
          break;
        case 6:
          *pCurrentFace = elems[i].nod[4] ;
          *(pCurrentFace+1) = elems[i].nod[5] ;
          *(pCurrentFace+2) = elems[i].nod[6] ;
          *(pCurrentFace+3) = elems[i].nod[7] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[16] ;
          *(pCurrentFace+7) = elems[i].nod[17] ;
          *(pCurrentFace+8) = elems[i].nod[18] ;
          *(pCurrentFace+9) = elems[i].nod[19] ;

          *pDispFace     = elems[i].nod[4];
          *(pDispFace+1)    = elems[i].nod[16];
          *(pDispFace+2)    = elems[i].nod[19];
          *(pDispFace+3) = elems[i].nod[16];
          *(pDispFace+4)    = elems[i].nod[25];
          *(pDispFace+5)    = elems[i].nod[19];
          *(pDispFace+6) = elems[i].nod[19];
          *(pDispFace+7)    = elems[i].nod[25];
          *(pDispFace+8)    = elems[i].nod[ 7];
          *(pDispFace+9) = elems[i].nod[25];
          *(pDispFace+10)   = elems[i].nod[18];
          *(pDispFace+11)   = elems[i].nod[ 7];

          *(pDispFace+12)= elems[i].nod[16];
          *(pDispFace+13)   = elems[i].nod[ 5];
          *(pDispFace+14)   = elems[i].nod[25];
          *(pDispFace+15)= elems[i].nod[ 5];
          *(pDispFace+16)   = elems[i].nod[17];
          *(pDispFace+17)   = elems[i].nod[25];
          *(pDispFace+18)= elems[i].nod[25];
          *(pDispFace+19)   = elems[i].nod[17];
          *(pDispFace+20)   = elems[i].nod[18];
          *(pDispFace+21)= elems[i].nod[17];
          *(pDispFace+22)   = elems[i].nod[ 6];
          *(pDispFace+23)   = elems[i].nod[18];
  /* ende */
          break;
      }
      *(pCurrentFace+4) = elems[i].nr ;
      *(pCurrentFace+5) = elems[i].group ;
      pFaceN += 10 ;
      pFaceN1 += 10 ;
      pCurrentFace += 10 ;
      numDisplayFaces += 1 ;
  /* erweiterung fuer He26 */
      *(pDispFace+24) = elems[i].nr ;
      *(pDispFace+25) = elems[i].group ;
      pDispFace += 26 ;
      numDispFaces += 8 ;
  /* ende */
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 20 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }
  pmaxd = pCurrentFace -10 ;  /* größter zulässiger DisplayFace-Pointer */

#if TEST
  t1=clock() ;
  deltaT = ((double)t1 - (double)t0)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesHe26: %i faces reduced to %i in %.2f seconds\n",
      numFaces, numDisplayFaces, deltaT) ;
#endif

  /* Suche freie Kanten des Modells */
  /* wenn 2 aufeinander folgende Flaechen zu einem Element gehoeren, ist eine Kante gefunden */

  /* nach Elementnummern sortieren */
  qsort (pfaces, numDisplayFaces, 10*sizeof(int), compareElnum) ;

  pFaceN = pfaces ;
  pFaceN1 = pfaces + 10 ;

  while ( pFaceN < pmaxd )                         /* bis zur vorletzten Fläche */
  {
    if ( *(pFaceN+4) == *(pFaceN1+4) )             /* sind beide Flaechen vom gleichen Element? */
    {
      if ( (i=commonEdge (pFaceN, pFaceN1)) != -1 )
      {
        *pDispFace = *(pFaceN+i);
        *(pDispFace+1) = *(pFaceN+i+6);
        if ( i == 3 ) i = -1;
        *(pDispFace+2) = *(pFaceN+i+1);
        pDispFace += 3;                            /* Knotentripel hinter Flächen speichern */
        numEdges+=2;
      }
      pFaceN1 += 10 ;                              /* alle Flächen eines Elements abfragen  */
      if ( pFaceN1 > pmaxd ) /* Überlauf abfangen */
      {
        pFaceN += 10 ;
        pFaceN1 = pFaceN + 10 ;
      }
    }
    else
    {
      pFaceN += 10 ;
      pFaceN1 = pFaceN + 10 ;
    }
  }

#if TEST
  t2=clock() ;
  deltaT = ((double)t2 - (double)t1)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFaces: %i free edges detected in %.2f seconds\n",
      numEdges, deltaT) ;
#endif

  *ptr=pDispFaceStart;
  *edges=numEdges;

  return numDispFaces ;
}




int selectDisplayFacesPe20 (Elements *elems, int numElems, int **ptr, int *edges) {
  /* waehlt Elementflaechen aus, alle doppelt vorkommenden Flaechen werden eliminiert.
     Freie Elementkanten werden gesucht.  */

  /* erweiterung fuer Pe20 */
  int numDispFaces=0;
  int *pDispFace;
  int *pDispFaceStart;
  /* ende */

  int numFaces, numDisplayFaces=0, i ;
  int numEdges=0;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax, *pmaxd ;
  clock_t t0, t1, t2 ;
  double deltaT ;
  extern int compareFaces () ;
  extern int compareElnum () ;
  extern void vdsort ( int *) ;
  extern int commonEdge (int *, int *) ;


  t0=clock() ;

  numFaces = 5 * numElems ;

  size = (10* numFaces+24*6*numElems ) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pfaces = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }


  pCurrentFace = pfaces ;

  /* use midside-nodes for surface extraction */
  for ( i = 0; i < numElems; i++ ) {
    *pCurrentFace = elems[i].nod[6] ;
    *(pCurrentFace+1) = elems[i].nod[10] ;
    *(pCurrentFace+2) = elems[i].nod[12] ;
    *(pCurrentFace+3) = elems[i].nod[9] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 1 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[7] ;
    *(pCurrentFace+1) = elems[i].nod[11] ;
    *(pCurrentFace+2) = elems[i].nod[13] ;
    *(pCurrentFace+3) = elems[i].nod[10] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 2 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[8] ;
    *(pCurrentFace+1) = elems[i].nod[ 9] ;
    *(pCurrentFace+2) = elems[i].nod[14] ;
    *(pCurrentFace+3) = elems[i].nod[11] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 3 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[ 8] ;
    *(pCurrentFace+1) = elems[i].nod[ 7] ;
    *(pCurrentFace+2) = elems[i].nod[ 6] ;
    *(pCurrentFace+3) = elems[i].nod[ 0] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 4 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[12] ;
    *(pCurrentFace+1) = elems[i].nod[13] ;
    *(pCurrentFace+2) = elems[i].nod[14] ;
    *(pCurrentFace+3) = elems[i].nod[ 3] ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 5 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
  }
  pmax = pCurrentFace -10 ;  /* größter zulässiger Face-Pointer */

  /* nach Knotennummern sortieren */
  qsort (pfaces, numFaces, 10*sizeof(int), compareFaces) ;

  /* erweiterung fuer Pe20-Triangles */
  size = (26* numFaces+24*5*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pDispFace = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pDispFace\n\n") ; exit(-1); }
  pDispFaceStart=pDispFace;
  /* ende */

  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 10 ;
              /* <= pmax, damit die letzte Fläche nicht verloren geht */
  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
    if ( compareFaces (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 20 ;
      pFaceN1 += 20 ; }
    else {
      i = *(pFaceN+4) ;
      switch ( *(pFaceN + 3) ) {
        case 1:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[1] ;
          *(pCurrentFace+2) = elems[i].nod[4] ;
          *(pCurrentFace+3) = elems[i].nod[3] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[ 6] ;
          *(pCurrentFace+7) = elems[i].nod[10] ;
          *(pCurrentFace+8) = elems[i].nod[12] ;
          *(pCurrentFace+9) = elems[i].nod[9] ;

  /* es folgen die Dreiecke fuer die Surfaces */
          *pDispFace     = elems[i].nod[1];
          *(pDispFace+1)    = elems[i].nod[10];
          *(pDispFace+2)    = elems[i].nod[ 6];
          *(pDispFace+3) = elems[i].nod[10];
          *(pDispFace+4)    = elems[i].nod[15];
          *(pDispFace+5)    = elems[i].nod[ 6];
          *(pDispFace+6) = elems[i].nod[ 6];
          *(pDispFace+7)    = elems[i].nod[15];
          *(pDispFace+8)    = elems[i].nod[ 0];
          *(pDispFace+9) = elems[i].nod[15];
          *(pDispFace+10)   = elems[i].nod[ 9];
          *(pDispFace+11)   = elems[i].nod[ 0];

          *(pDispFace+12)= elems[i].nod[10];
          *(pDispFace+13)   = elems[i].nod[ 4];
          *(pDispFace+14)   = elems[i].nod[15];
          *(pDispFace+15)= elems[i].nod[ 4];
          *(pDispFace+16)   = elems[i].nod[12];
          *(pDispFace+17)   = elems[i].nod[15];
          *(pDispFace+18)= elems[i].nod[15];
          *(pDispFace+19)   = elems[i].nod[12];
          *(pDispFace+20)   = elems[i].nod[ 9];
          *(pDispFace+21)= elems[i].nod[12];
          *(pDispFace+22)   = elems[i].nod[ 3];
          *(pDispFace+23)   = elems[i].nod[ 9];
  /* ende */
          break;
        case 2:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[5] ;
          *(pCurrentFace+3) = elems[i].nod[4] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[ 7] ;
          *(pCurrentFace+7) = elems[i].nod[11] ;
          *(pCurrentFace+8) = elems[i].nod[13] ;
          *(pCurrentFace+9) = elems[i].nod[10] ;

          *pDispFace     = elems[i].nod[ 2];
          *(pDispFace+1)    = elems[i].nod[11];
          *(pDispFace+2)    = elems[i].nod[ 7];
          *(pDispFace+3) = elems[i].nod[11];
          *(pDispFace+4)    = elems[i].nod[16];
          *(pDispFace+5)    = elems[i].nod[ 7];
          *(pDispFace+6) = elems[i].nod[ 7];
          *(pDispFace+7)    = elems[i].nod[16];
          *(pDispFace+8)    = elems[i].nod[ 1];
          *(pDispFace+9) = elems[i].nod[16];
          *(pDispFace+10)   = elems[i].nod[10];
          *(pDispFace+11)   = elems[i].nod[ 1];

          *(pDispFace+12)= elems[i].nod[11];
          *(pDispFace+13)   = elems[i].nod[ 5];
          *(pDispFace+14)   = elems[i].nod[16];
          *(pDispFace+15)= elems[i].nod[ 5];
          *(pDispFace+16)   = elems[i].nod[13];
          *(pDispFace+17)   = elems[i].nod[16];
          *(pDispFace+18)= elems[i].nod[16];
          *(pDispFace+19)   = elems[i].nod[13];
          *(pDispFace+20)   = elems[i].nod[10];
          *(pDispFace+21)= elems[i].nod[13];
          *(pDispFace+22)   = elems[i].nod[ 4];
          *(pDispFace+23)   = elems[i].nod[10];
   /* ende */
          break;
        case 3:
          *pCurrentFace = elems[i].nod[2] ;
          *(pCurrentFace+1) = elems[i].nod[0] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[5] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[ 8] ;
          *(pCurrentFace+7) = elems[i].nod[ 9] ;
          *(pCurrentFace+8) = elems[i].nod[14] ;
          *(pCurrentFace+9) = elems[i].nod[11] ;

          *pDispFace     = elems[i].nod[ 0];
          *(pDispFace+1)    = elems[i].nod[ 9];
          *(pDispFace+2)    = elems[i].nod[ 8];
          *(pDispFace+3) = elems[i].nod[ 9];
          *(pDispFace+4)    = elems[i].nod[17];
          *(pDispFace+5)    = elems[i].nod[ 8];
          *(pDispFace+6) = elems[i].nod[ 8];
          *(pDispFace+7)    = elems[i].nod[17];
          *(pDispFace+8)    = elems[i].nod[ 2];
          *(pDispFace+9) = elems[i].nod[17];
          *(pDispFace+10)   = elems[i].nod[11];
          *(pDispFace+11)   = elems[i].nod[ 2];

          *(pDispFace+12)= elems[i].nod[ 9];
          *(pDispFace+13)   = elems[i].nod[ 3];
          *(pDispFace+14)   = elems[i].nod[17];
          *(pDispFace+15)= elems[i].nod[ 3];
          *(pDispFace+16)   = elems[i].nod[14];
          *(pDispFace+17)   = elems[i].nod[17];
          *(pDispFace+18)= elems[i].nod[17];
          *(pDispFace+19)   = elems[i].nod[14];
          *(pDispFace+20)   = elems[i].nod[11];
          *(pDispFace+21)= elems[i].nod[14];
          *(pDispFace+22)   = elems[i].nod[ 5];
          *(pDispFace+23)   = elems[i].nod[11];
 /* ende */
          break;
        case 4:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[1] ;
          *(pCurrentFace+3) = elems[i].nod[0] ;
   /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[ 8] ;
          *(pCurrentFace+7) = elems[i].nod[ 7] ;
          *(pCurrentFace+8) = elems[i].nod[ 6] ;
          *(pCurrentFace+9) = elems[i].nod[ 0] ;

          *pDispFace     = elems[i].nod[ 2];
          *(pDispFace+1)    = elems[i].nod[ 7];
          *(pDispFace+2)    = elems[i].nod[ 8];
          *(pDispFace+3) = elems[i].nod[ 7];
          *(pDispFace+4)    = elems[i].nod[18];
          *(pDispFace+5)    = elems[i].nod[ 8];
          *(pDispFace+6) = elems[i].nod[ 8];
          *(pDispFace+7)    = elems[i].nod[18];
          *(pDispFace+8)    = elems[i].nod[ 0];
          *(pDispFace+9) = elems[i].nod[18];
          *(pDispFace+10)   = elems[i].nod[ 0];
          *(pDispFace+11)   = elems[i].nod[ 0];

          *(pDispFace+12)= elems[i].nod[ 7];
          *(pDispFace+13)   = elems[i].nod[ 1];
          *(pDispFace+14)   = elems[i].nod[18];
          *(pDispFace+15)= elems[i].nod[ 1];
          *(pDispFace+16)   = elems[i].nod[ 6];
          *(pDispFace+17)   = elems[i].nod[18];
          *(pDispFace+18)= elems[i].nod[18];
          *(pDispFace+19)   = elems[i].nod[ 6];
          *(pDispFace+20)   = elems[i].nod[ 0];
          *(pDispFace+21)= elems[i].nod[ 6];
          *(pDispFace+22)   = elems[i].nod[ 0];
          *(pDispFace+23)   = elems[i].nod[ 0];
  /* ende */
         break;
        case 5:
          *pCurrentFace = elems[i].nod[3] ;
          *(pCurrentFace+1) = elems[i].nod[4] ;
          *(pCurrentFace+2) = elems[i].nod[5] ;
          *(pCurrentFace+3) = elems[i].nod[3] ;
  /* erweiterung fuer He26 */
          *(pCurrentFace+6) = elems[i].nod[12] ;
          *(pCurrentFace+7) = elems[i].nod[13] ;
          *(pCurrentFace+8) = elems[i].nod[14] ;
          *(pCurrentFace+9) = elems[i].nod[ 3] ;

          *pDispFace     = elems[i].nod[4];
          *(pDispFace+1)    = elems[i].nod[13];
          *(pDispFace+2)    = elems[i].nod[12];
          *(pDispFace+3) = elems[i].nod[13];
          *(pDispFace+4)    = elems[i].nod[19];
          *(pDispFace+5)    = elems[i].nod[12];
          *(pDispFace+6) = elems[i].nod[12];
          *(pDispFace+7)    = elems[i].nod[19];
          *(pDispFace+8)    = elems[i].nod[ 3];
          *(pDispFace+9) = elems[i].nod[19];
          *(pDispFace+10)   = elems[i].nod[ 3];
          *(pDispFace+11)   = elems[i].nod[ 3];

          *(pDispFace+12)= elems[i].nod[13];
          *(pDispFace+13)   = elems[i].nod[ 5];
          *(pDispFace+14)   = elems[i].nod[19];
          *(pDispFace+15)= elems[i].nod[ 5];
          *(pDispFace+16)   = elems[i].nod[14];
          *(pDispFace+17)   = elems[i].nod[19];
          *(pDispFace+18)= elems[i].nod[19];
          *(pDispFace+19)   = elems[i].nod[14];
          *(pDispFace+20)   = elems[i].nod[ 3];
          *(pDispFace+21)= elems[i].nod[14];
          *(pDispFace+22)   = elems[i].nod[ 3];
          *(pDispFace+23)   = elems[i].nod[ 3];
  /* ende */
          break;
      }
      *(pCurrentFace+4) = elems[i].nr ;
      *(pCurrentFace+5) = elems[i].group ;
      pFaceN += 10 ;
      pFaceN1 += 10 ;
      pCurrentFace += 10 ;
      numDisplayFaces += 1 ;
  /* erweiterung fuer He26 */
      *(pDispFace+24) = elems[i].nr ;
      *(pDispFace+25) = elems[i].group ;
      pDispFace += 26 ;
      numDispFaces += 8 ;
  /* ende */
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 20 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }
  pmaxd = pCurrentFace -10 ;  /* größter zulässiger DisplayFace-Pointer */

#if TEST
  t1=clock() ;
  deltaT = ((double)t1 - (double)t0)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesPe20: %i faces reduced to %i in %.2f seconds\n",
      numFaces, numDisplayFaces, deltaT) ;
#endif

  /* Suche freie Kanten des Modells */
  /* wenn 2 aufeinander folgende Flaechen zu einem Element gehoeren, ist eine Kante gefunden */

  /* nach Elementnummern sortieren */
  qsort (pfaces, numDisplayFaces, 10*sizeof(int), compareElnum) ;

  pFaceN = pfaces ;
  pFaceN1 = pfaces + 10 ;

  while ( pFaceN < pmaxd )                         /* bis zur vorletzten Fläche */
  {
    if ( *(pFaceN+4) == *(pFaceN1+4) )             /* sind beide Flaechen vom gleichen Element? */
    {
      if ( (i=commonEdge (pFaceN, pFaceN1)) != -1 )
      {
        *pDispFace = *(pFaceN+i);
        *(pDispFace+1) = *(pFaceN+i+6);
        if ( i == 3 ) i = -1;
        *(pDispFace+2) = *(pFaceN+i+1);
        pDispFace += 3;                            /* Knotentripel hinter Flächen speichern */
        numEdges+=2;
      }
      pFaceN1 += 10 ;                              /* alle Flächen eines Elements abfragen  */
      if ( pFaceN1 > pmaxd ) /* Überlauf abfangen */
      {
        pFaceN += 10 ;
        pFaceN1 = pFaceN + 10 ;
      }
    }
    else
    {
      pFaceN += 10 ;
      pFaceN1 = pFaceN + 10 ;
    }
  }

#if TEST
  t2=clock() ;
  deltaT = ((double)t2 - (double)t1)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFaces: %i free edges detected in %.2f seconds\n",
      numEdges, deltaT) ;
#endif

  *ptr=pDispFaceStart;
  *edges=numEdges;

  return numDispFaces ;
}



int selectDisplayFacesTet10 (Elements *elems, int numElems, int **ptr, int *edges) {
  /* wählt äußere Elementflächen aus, alle doppelt vorkommenden Flächen
     werden eliminiert
     Freie Elementkanten werden gesucht.  */

  /* erweiterung fuer Tet10 */
  int numDispFaces=0;
  int *pDispFace;
  int *pDispFaceStart;
  /* ende */

  int numFaces, numDisplayFaces=0, i ;
  int numEdges=0;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax, *pmaxd ;
  clock_t t0, t1, t2 ;
  double deltaT ;
  extern int compareFaces () ;
  extern int compareElnum () ;
  extern void vdsort ( int *) ;
  extern int commonEdge (int *, int *) ;


  t0=clock() ;

  numFaces = 4 * numElems ;

  size = (10* numFaces+14*6*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pfaces = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }


  pCurrentFace = pfaces ;

  for ( i = 0; i < numElems; i++ ) {
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[1] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 1 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[1] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 2 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[2] ;
    *(pCurrentFace+1) = elems[i].nod[0] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 3 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[1] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 4 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 10 ;
  }
  pmax = pCurrentFace -10 ;  /* größter zulässiger Face-Pointer */

  qsort (pfaces, numFaces, 10*sizeof(int), compareFaces) ;

  /* erweiterung fuer Tet10-Triangles */
  size = (16* numFaces+12*4*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pDispFace = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pDispFace\n\n") ; exit(-1); }
  pDispFaceStart=pDispFace;
  /* ende */

  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 10 ;
              /* <= pmax, damit die letzte Fläche nicht verloren geht */
  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
    if ( compareFaces (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 20 ;
      pFaceN1 += 20 ; }
    else {
      i = *(pFaceN+4) ;
      switch ( *(pFaceN + 3) ) {
        case 1:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[1] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[0] ;
  /* erweiterung fuer Tet10 */
          *(pCurrentFace+6) = elems[i].nod[ 4] ;
          *(pCurrentFace+7) = elems[i].nod[ 8] ;
          *(pCurrentFace+8) = elems[i].nod[7] ;
          *(pCurrentFace+9) = elems[i].nod[4] ;

  /* es folgen die Dreiecke fuer die Surfaces */
          *pDispFace     = elems[i].nod[0];
          *(pDispFace+1)    = elems[i].nod[ 4];
          *(pDispFace+2)    = elems[i].nod[ 7];
      *(pDispFace+3) = elems[i].nr ;
      *(pDispFace+4) = elems[i].group ;
          *(pDispFace+5) = elems[i].nod[7 ];
          *(pDispFace+6)    = elems[i].nod[4];
          *(pDispFace+7)    = elems[i].nod[8];
      *(pDispFace+8) = elems[i].nr ;
      *(pDispFace+9) = elems[i].group ;
          *(pDispFace+10) = elems[i].nod[ 8];
          *(pDispFace+11)    = elems[i].nod[ 4];
          *(pDispFace+12)    = elems[i].nod[ 1];
      *(pDispFace+13) = elems[i].nr ;
      *(pDispFace+14) = elems[i].group ;
          *(pDispFace+15) = elems[i].nod[ 7];
          *(pDispFace+16)   = elems[i].nod[ 8];
          *(pDispFace+17)   = elems[i].nod[ 3];
      *(pDispFace+18) = elems[i].nr ;
      *(pDispFace+19) = elems[i].group ;
  /* ende */
          break;
        case 2:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[1] ;
  /* erweiterung fuer Tet10 */
          *(pCurrentFace+6) = elems[i].nod[ 5] ;
          *(pCurrentFace+7) = elems[i].nod[ 9] ;
          *(pCurrentFace+8) = elems[i].nod[8] ;
          *(pCurrentFace+9) = elems[i].nod[5] ;

  /* es folgen die Dreiecke fuer die Surfaces */
          *pDispFace     = elems[i].nod[1];
          *(pDispFace+1)    = elems[i].nod[ 5];
          *(pDispFace+2)    = elems[i].nod[ 8];
      *(pDispFace+3) = elems[i].nr ;
      *(pDispFace+4) = elems[i].group ;
          *(pDispFace+5) = elems[i].nod[8 ];
          *(pDispFace+6)    = elems[i].nod[5];
          *(pDispFace+7)    = elems[i].nod[9];
      *(pDispFace+8) = elems[i].nr ;
      *(pDispFace+9) = elems[i].group ;
          *(pDispFace+10) = elems[i].nod[ 9];
          *(pDispFace+11)    = elems[i].nod[ 5];
          *(pDispFace+12)    = elems[i].nod[ 2];
      *(pDispFace+13) = elems[i].nr ;
      *(pDispFace+14) = elems[i].group ;
          *(pDispFace+15) = elems[i].nod[ 8];
          *(pDispFace+16)   = elems[i].nod[ 9];
          *(pDispFace+17)   = elems[i].nod[ 3];
      *(pDispFace+18) = elems[i].nr ;
      *(pDispFace+19) = elems[i].group ;
  /* ende */
          break;
        case 3:
          *pCurrentFace = elems[i].nod[2] ;
          *(pCurrentFace+1) = elems[i].nod[0] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[2] ;
  /* erweiterung fuer Tet10 */
          *(pCurrentFace+6) = elems[i].nod[ 6] ;
          *(pCurrentFace+7) = elems[i].nod[ 7] ;
          *(pCurrentFace+8) = elems[i].nod[9] ;
          *(pCurrentFace+9) = elems[i].nod[6] ;

  /* es folgen die Dreiecke fuer die Surfaces */
          *pDispFace     = elems[i].nod[2];
          *(pDispFace+1)    = elems[i].nod[ 6];
          *(pDispFace+2)    = elems[i].nod[ 9];
      *(pDispFace+3) = elems[i].nr ;
      *(pDispFace+4) = elems[i].group ;
          *(pDispFace+5) = elems[i].nod[9 ];
          *(pDispFace+6)    = elems[i].nod[6];
          *(pDispFace+7)    = elems[i].nod[7];
      *(pDispFace+8) = elems[i].nr ;
      *(pDispFace+9) = elems[i].group ;
          *(pDispFace+10) = elems[i].nod[ 7];
          *(pDispFace+11)    = elems[i].nod[ 6];
          *(pDispFace+12)    = elems[i].nod[ 0];
      *(pDispFace+13) = elems[i].nr ;
      *(pDispFace+14) = elems[i].group ;
          *(pDispFace+15) = elems[i].nod[ 9];
          *(pDispFace+16)   = elems[i].nod[ 7];
          *(pDispFace+17)   = elems[i].nod[ 3];
      *(pDispFace+18) = elems[i].nr ;
      *(pDispFace+19) = elems[i].group ;
  /* ende */
          break;
        case 4:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[1] ;
          *(pCurrentFace+3) = elems[i].nod[0] ;
  /* erweiterung fuer Tet10 */
          *(pCurrentFace+6) = elems[i].nod[ 6] ;
          *(pCurrentFace+7) = elems[i].nod[ 5] ;
          *(pCurrentFace+8) = elems[i].nod[4] ;
          *(pCurrentFace+9) = elems[i].nod[6] ;

  /* es folgen die Dreiecke fuer die Surfaces */
          *pDispFace     = elems[i].nod[0];
          *(pDispFace+1)    = elems[i].nod[ 6];
          *(pDispFace+2)    = elems[i].nod[ 4];
      *(pDispFace+3) = elems[i].nr ;
      *(pDispFace+4) = elems[i].group ;
          *(pDispFace+5) = elems[i].nod[4 ];
          *(pDispFace+6)    = elems[i].nod[6];
          *(pDispFace+7)    = elems[i].nod[5];
      *(pDispFace+8) = elems[i].nr ;
      *(pDispFace+9) = elems[i].group ;
          *(pDispFace+10) = elems[i].nod[ 5];
          *(pDispFace+11)    = elems[i].nod[ 6];
          *(pDispFace+12)    = elems[i].nod[ 2];
      *(pDispFace+13) = elems[i].nr ;
      *(pDispFace+14) = elems[i].group ;
          *(pDispFace+15) = elems[i].nod[ 4];
          *(pDispFace+16)   = elems[i].nod[ 5];
          *(pDispFace+17)   = elems[i].nod[ 1];
      *(pDispFace+18) = elems[i].nr ;
      *(pDispFace+19) = elems[i].group ;
  /* ende */
          break;
      }
      *(pCurrentFace+4) = elems[i].nr ;
      *(pCurrentFace+5) = elems[i].group ;
      pFaceN += 10 ;
      pFaceN1 += 10 ;
      pCurrentFace += 10 ;
      numDisplayFaces += 1 ;
  /* erweiterung fuer Tet10*/
      pDispFace += 20 ;
      numDispFaces += 4 ;
  /* ende */
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 20 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }
  pmaxd = pCurrentFace -10 ;  /* größter zulässiger DisplayFace-Pointer */

#if TEST
  t1=clock() ;
  deltaT = ((double)t1 - (double)t0)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesTet10: %i faces reduced to %i in %.2f seconds\n",
      numFaces, numDisplayFaces, deltaT) ;
#endif

  /* Suche freie Kanten des Modells */
  /* wenn 2 aufeinander folgende Flaechen zu einem Element gehoeren, ist eine Kante gefunden */

  /* nach Elementnummern sortieren */
  qsort (pfaces, numDisplayFaces, 10*sizeof(int), compareElnum) ;

  pFaceN = pfaces ;
  pFaceN1 = pfaces + 10 ;

  while ( pFaceN < pmaxd )                         /* bis zur vorletzten Fläche */
  {
    if ( *(pFaceN+4) == *(pFaceN1+4) )             /* sind beide Flaechen vom gleichen Element? */
    {
      if ( (i=commonEdge3 (pFaceN, pFaceN1)) != -1 )
      {
        *pDispFace = *(pFaceN+i);
        *(pDispFace+1) = *(pFaceN+i+6);
        if ( i == 2 ) i = -1;
        *(pDispFace+2) = *(pFaceN+i+1);
        pDispFace += 3;                            /* Knotentripel hinter Flächen speichern */
        numEdges+=2;
      }
      pFaceN1 += 10 ;                              /* alle Flächen eines Elements abfragen  */
      if ( pFaceN1 > pmaxd )    /* Überlauf abfangen */
      {
        pFaceN += 10 ;
        pFaceN1 = pFaceN + 10 ;
      }
    }
    else
    {
      pFaceN += 10 ;
      pFaceN1 = pFaceN + 10 ;
    }
  }

#if TEST
  t2=clock() ;
  deltaT = ((double)t2 - (double)t1)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesTet10: %i free edges detected in %.2f seconds\n",
      numEdges, deltaT) ;
#endif

  *ptr=pDispFaceStart;
  *edges=numEdges;

  return numDispFaces ;
}


int selectDisplayFacesTet4 (Elements *elems, int numElems, int **ptr, int *edges) {
  /* wählt äußere Elementflächen aus, alle doppelt vorkommenden Flächen
     werden eliminiert
     Freie Elementkanten werden gesucht.  */

/* ToDo : weitere Elementtypen, Element-Auswahllisten */

  int numFaces, numDisplayFaces=0, i ;
  int numEdges=0;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax, *pmaxd ;
  clock_t t0, t1, t2 ;
  double deltaT ;
/*  extern int compareFaces (int *, int *) ;   */
  extern int compareFaces () ;
  extern int compareElnum () ;
  extern void vdsort ( int *) ;
  extern int commonEdge (int *, int *) ;

  t0=clock() ;

  numFaces = 4 * numElems ;
  size = (1* numFaces+6*6*numElems) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;

  if ( (pfaces = (int *)malloc( size )) == NULL )
   { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }

  pCurrentFace = pfaces ;

  for ( i = 0; i < numElems; i++ ) {
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[1] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 1 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[1] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 2 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[2] ;
    *(pCurrentFace+1) = elems[i].nod[0] ;
    *(pCurrentFace+2) = elems[i].nod[3] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 3 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    *(pCurrentFace+2) = elems[i].nod[1] ;
    *(pCurrentFace+3) = MAX_NODE_NR ;
    vdsort( pCurrentFace ) ;
    *(pCurrentFace+3) = 4 ;
    *(pCurrentFace+4) = i ;
    pCurrentFace += 6 ;
  }
  pmax = pCurrentFace -6 ;  /* größter zulässiger Face-Pointer */

  /* nach Knotennummern sortieren */
  qsort (pfaces, numFaces, 6*sizeof(int), compareFaces) ;

  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 6 ;

  /* <= pmax, damit die letzte Fläche nicht verloren geht */
  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
    if ( compareFaces (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 12 ;
      pFaceN1 += 12 ; }
    else {
      i = *(pFaceN+4) ;
      switch ( *(pFaceN + 3) ) {
        case 1:
          /* Die Felder werden gleichzeitig abgefragt (pFaceN) */
          /* und neu beschrieben (pCurrentFace) */
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[1] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[0] ;
          break;
        case 2:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[1] ;
          break;
        case 3:
          *pCurrentFace = elems[i].nod[2] ;
          *(pCurrentFace+1) = elems[i].nod[0] ;
          *(pCurrentFace+2) = elems[i].nod[3] ;
          *(pCurrentFace+3) = elems[i].nod[2] ;
          break;
        case 4:
          *pCurrentFace = elems[i].nod[0] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[1] ;
          *(pCurrentFace+3) = elems[i].nod[0] ;
          break;
      }
      *(pCurrentFace+4) = elems[i].nr ;
      *(pCurrentFace+5) = elems[i].group ;
      pFaceN += 6 ;
      pFaceN1 += 6 ;
      pCurrentFace += 6 ;
      numDisplayFaces += 1 ;
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 12 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }
  pmaxd = pCurrentFace -6 ;  /* größter zulässiger DisplayFace-Pointer */

#if TEST
  t1=clock() ;
  deltaT = ((double)t1 - (double)t0)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFacesTet4: %i faces reduced to %i in %.2f seconds\n"
  , numFaces, numDisplayFaces, deltaT) ;
#endif

  /* Suche freie Kanten des Modells */
  /* wenn 2 aufeinander folgende Flaechen zu einem Element gehoeren, ist eine Kante gefunden */

  /* nach Elementnummern sortieren */
  qsort (pfaces, numDisplayFaces, 6*sizeof(int), compareElnum) ;

  pFaceN = pfaces ;
  pFaceN1 = pfaces + 6 ;

  while ( pFaceN < pmaxd )    /* bis zur vorletzten Fläche */
  {
    if ( *(pFaceN+4) == *(pFaceN1+4) )  /* sind beide Flaechen vom gleichen Element? */
    {
      if ( (i=commonEdge (pFaceN, pFaceN1)) != -1 )
      {
        *pCurrentFace = *(pFaceN+i);
        if ( i == 3 ) i = -1;
        *(pCurrentFace+1) = *(pFaceN+i+1);
        pCurrentFace += 2;              /* Knotenpaare fortlaufend hinter Flächen speichern */
        numEdges++;
      }
      pFaceN1 += 6 ;                            /* alle Flächen eines Elements abfragen  */
      if ( pFaceN1 > pmaxd )   /* Überlauf abfangen */
      {
        pFaceN += 6 ;
        pFaceN1 = pFaceN + 6 ;
      }
    }
    else
    {
      pFaceN += 6 ;
      pFaceN1 = pFaceN + 6 ;
    }
  }

#if TEST
  t2=clock() ;
  deltaT = ((double)t2 - (double)t1)/(double)CLOCKS_PER_SEC ;
  printf("\n selectDisplayFaces: %i free edges detected in %.2f seconds\n",
      numEdges, deltaT) ;
#endif

  *ptr=pfaces;
  *edges=numEdges;

  return numDisplayFaces ;
}




int commonEdge (int *a, int *b) {
  int i, j, j1;
  for ( i=0; i < 3; i++ )
  {
    for ( j=0; j < 4; j++ )
    {
      if ( a[i] == b[j] )  /* erster gemeinsamer Knoten */
      {
        if ( i == 1 || i == 2 ) return i;
        for ( j1=0; j1 < 4; j1++ )
        {
          if ( a[1] == b[j1] )  return 0;
        }
        return 3;
      }
    }
  }
  return -1;
}

int commonEdge3 (int *a, int *b) {
  int i, j, j1;
  for ( i=0; i < 2; i++ )
  {
    for ( j=0; j < 3; j++ )
    {
      if ( a[i] == b[j] )  /* erster gemeinsamer Knoten */
      {
        if ( i == 1) return i;
        for ( j1=0; j1 < 3; j1++ )
        {
          if ( a[1] == b[j1] )  return 0;
        }
        return 2;
      }
    }
  }
  return -1;
}

int compareFaces (int *a, int *b) {
  /* wird von qsort aufgerufen, vergleicht die ersten drei Zahlen von
     Integer-Feldern */

  if ( a[0] < b[0] )
    return -1 ;
  else if ( a[0] > b[0] )
    return 1 ;
  else if ( a[1] < b[1] )
    return -1 ;
  else if ( a[1] > b[1] )
    return 1 ;
  else if ( a[2] < b[2] )
    return -1 ;
  else if ( a[2] > b[2] )
    return 1 ;
  else
    return 0 ;
}

int compareElnum (int *a, int *b) {
  /* wird von qsort aufgerufen, vergleicht die fünfte Zahl (Elem-Nr.) von
     Integer-Feldern */

  if ( a[4] < b[4] )
    return -1 ;
  else if ( a[4] > b[4] )
    return 1 ;
  else
    return 0 ;
}

void vdsort ( int *a ) {
  /* belegt die ersten drei Elemente eines 4er Arrays mit den drei kleinsten
     Werten */
  register int n0, n1, n2, n3 ;

  if ( a[1] < a[0] ) {
    n0 = a[1] ;
    n1 = a[0] ; }
  else {
    n0 = a[0] ;
    n1 = a[1] ; }

  if ( a[3] < a[2] ) {
    n2 = a[3] ;
    n3 = a[2] ; }
  else {
    n2 = a[2] ;
    n3 = a[3] ; }

  if ( n2 < n0 ) {
    a[0] = n2 ;
    if ( n3 < n0 ) {
      a[1] = n3 ;
      a[2] = n0 ; }
    else if ( n3 < n1 ) {
      a[1] = n0 ;
      a[2] = n3 ; }
    else {
      a[1] = n0 ;
      a[2] = n1 ; }
  }
  else {
    a[0] = n0 ;
    if ( n2 < n1 ) {
      a[1] = n2 ;
      if ( n3 < n1 )
        a[2] = n3 ;
      else
        a[2] = n1 ;
    }
    else {
      a[1] = n1 ;
      a[2] = n2 ; }
  }
}


void vdsort2 ( int *a ) {
  /* belegt die ersten zwei Elemente eines zweier Arrays mit den zwei kleinsten
     Werten */
  int n ;

  if ( a[1] < a[0] ) {
    n = a[1] ;
    a[1]=a[0] ;
    a[0]=n; 
  }
  
}


int compareFaces2 (int *a, int *b) {
  /* wird von qsort aufgerufen, vergleicht die ersten zwei Zahlen von
     Integer-Feldern */

  if ( a[0] < b[0] )
    return -1 ;
  else if ( a[0] > b[0] )
    return 1 ;
  else if ( a[1] < b[1] )
    return -1 ;
  else if ( a[1] > b[1] )
    return 1 ;
  else
    return 0 ;
}

/* store the free edges of unconnected tr3 in *edges */
int findCTri3Edges(Elements *elems, int numElems, int **edges)
{
  int numFaces, numDisplayFaces=0, i;
  long long size ;
  int *pfaces, *pCurrentFace, *pFaceN, *pFaceN1, *pmax;

  numFaces = 3 * numElems ;
  size = (numFaces*5) * sizeof(int) ;
  if ( size < 1920 ) size = 1920;
  if ( (pfaces = (int *)malloc( size+1 )) == NULL )
  { printf("\n\n ERROR: malloc pfaces\n\n") ; exit(-1); }

  pCurrentFace = pfaces ;

  for ( i = 0; i < numElems; i++ )
  {
    *pCurrentFace = elems[i].nod[0] ;
    *(pCurrentFace+1) = elems[i].nod[1] ;
    vdsort2( pCurrentFace ) ;
    *(pCurrentFace+2) = 1 ;
    *(pCurrentFace+3) = i ;
    pCurrentFace+=5 ;
    *pCurrentFace = elems[i].nod[1] ;
    *(pCurrentFace+1) = elems[i].nod[2] ;
    vdsort2( pCurrentFace ) ;
    *(pCurrentFace+2) = 2 ;
    *(pCurrentFace+3) = i ;
    pCurrentFace+=5 ;
    *pCurrentFace = elems[i].nod[2] ;
    *(pCurrentFace+1) = elems[i].nod[0] ;
    vdsort2( pCurrentFace ) ;
    *(pCurrentFace+2) = 3 ;
    *(pCurrentFace+3) = i ;
    pCurrentFace+=5 ;
  }
  pmax = pCurrentFace-5 ;  /* größter zulässiger Face-Pointer */

  /* nach Knotennummern sortieren */
  qsort (pfaces, numFaces, 5*sizeof(int), (void *)compareFaces2) ;
/*  for(i=0;i<numFaces;i++)  printf("f1: %d %d\n",*(pfaces+i*5),*(pfaces+i*5+1));  */ 

  /* store just the unique edges */
  pCurrentFace = pfaces ;
  pFaceN = pfaces ;
  pFaceN1 = pfaces + 5 ;

  while ( pFaceN <= pmax ) {  /* pFaceN1 wird am Ende zurückgesetzt */
/*      printf("f1: %d %d f2:%d %d\n",*pFaceN,*(pFaceN+1),*pFaceN1,*(pFaceN1+1)); */
    if ( compareFaces2 (pFaceN, pFaceN1) == 0 ) {   /* identische nodes: 2 flaechen ueberspringen */
      pFaceN += 10  ;
      pFaceN1 += 10  ; }
    else {
      i = *(pFaceN+3) ;
      switch ( *(pFaceN + 2) ) {
        case 1:
          *pCurrentFace = elems[i].nod[0] ;          /* Feld wird gleichzeitig abgefragt (pFaceN) */
          *(pCurrentFace+1) = elems[i].nod[1] ;      /* und neu beschrieben (pCurrentFace) */
          *(pCurrentFace+2) = elems[i].nod[2] ;      /* 3. node (nicht auf edge) */
          break;
        case 2:
          *pCurrentFace = elems[i].nod[1] ;
          *(pCurrentFace+1) = elems[i].nod[2] ;
          *(pCurrentFace+2) = elems[i].nod[0] ;      /* 3. node (nicht auf edge) */
          break;
        case 3:
          *pCurrentFace = elems[i].nod[2] ;
          *(pCurrentFace+1) = elems[i].nod[0] ;
          *(pCurrentFace+2) = elems[i].nod[1] ;      /* 3. node (nicht auf edge) */
          break;
      }
      *(pCurrentFace+3) = i ;
      *(pCurrentFace+4) = elems[i].group ;
      pFaceN += 5 ;
      pFaceN1 += 5 ;
      pCurrentFace += 5 ;
      numDisplayFaces++ ;
    }
    if ( pFaceN1 > pmax )  pFaceN1 -= 10 ;  /* muss <= pmax sein. Vergleich
       ist dann falsch, da gleiche Flächen nur doppelt auftreten können */
  }

  *edges=pfaces;

  return(numDisplayFaces) ;
}

