/* $Id$   
*/

*/   stl2pat - read in STL file and write out Patran Neutral file    */

*/  07 May 99  DSC  Created  */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define IN 1  /* inside a word */
#define OUT 0 /* outside a word */
#define END -1 /* finished a word */

/* declare File type for input and output files
   input_file and output_file are pointer variables */
FILE * input_file;
FILE * output_file;
char line[1000];
char word[1000];

struct node {
            float x ;
            float y ;
            float z ;
            struct node *next;
            } example;

struct node *start;
struct node *last;

struct element {
               int ielm0;
               int ielm1;
               int ielm2;
               struct element *next;
               } example2;

struct element *start_el;
struct element *last_el;

int getline();
void getword();
int wrt_title_card(void);
int wrt_summary(int in,int irec);
int wrt_nodes(struct node **start);
int wrt_elements(struct element **start_el);
void create_node(float x, float y, float z);
void sl_store(struct node *i, struct node **start, struct node **last);
void create_element(int ielm0, int ielm1, int ielm2);
void sl_store_el(struct element *i,struct element **start,struct element **last);

/*---------------------------------------------------------------------------------*/

int getline()
{
   int c, i;
   extern char line[];

   for (i = 0; i < 999 &&
               ((c = getc(input_file)) != EOF) &&
               (c != '\n') ; ++i) 
   {
      line[i] = c;
   }

   if (c == '\n')
   {
      line[i] = c;
      ++i;
   }

   line[i] = '\0';
   return i;

}

/*---------------------------------------------------------------------------------*/

void getword()
{
   int c, i;
   extern char line[];
   extern char word[];
   int state;
   int icount = 0;

   state = OUT;


   for ( i = 0; i < 999 &&
             ( (c = line[i]) != EOF) &&
             (state != END) ; ++i)
   {

      if ( c == ' ' || c == '\n' || c == '\t')
      {
         if (state == IN)
         {
            state = END;
            word[icount] = '\0';
         }
         else
         {
            state = OUT;
         }
      }
      else
      {
         state = IN;
         word[icount] = c;
         icount = icount + 1;
      }
   }

}

/*---------------------------------------------------------------------------------*/

int wrt_title_card(void)
{
   int ipkt=25,id=0,iv=0,kc=1;
   int n1,n2,n3,n4,n5;

   n1=n2=n3=n4=n5=0; 

   fprintf(output_file,"%2d%8d%8d%8d%8d%8d%8d%8d%8d \n",
             ipkt,id,iv,kc,n1,n2,n3,n4,n5);
   fprintf(output_file,"STL file translated into elements\n");

   return 0;
}

/*---------------------------------------------------------------------------------*/

int wrt_summary(int in,int irec)
{
   int ipkt=26,id=0,iv=0,kc=1;
   int n1,n2,n3,n4,n5;

   char month[12][4] = { "Jan\0","Feb\0","Mar\0","Apr\0",
                         "May\0","Jun\0","Jul\0","Aug\0",
                         "Sep\0","Oct\0","Nov\0","Dec\0"};  
                          

   time_t current_time;
   struct tm *lt;
   

   n1 = in;
   n2 = irec;
   n3=n4=0;
   n5 = -1;

   fprintf(output_file,"%2d%8d%8d%8d%8d%8d%8d%8d%8d \n",
             ipkt,id,iv,kc,n1,n2,n3,n4,n5);

   current_time = time(0);

   lt = localtime(&current_time);

   fprintf(output_file,"%d-%s-%d 2.5\n",
         lt->tm_mday,month[lt->tm_mon],lt->tm_year);

   return 0;
}

/*---------------------------------------------------------------------------------*/

int wrt_nodes(struct node **start)
{
   int ipkt=1;
   int id=0;
   int i,iv=0,kc=2;
   int n1,n2,n3,n4,n5;
   int pspc1,pspc2,pspc3,pspc4,pspc5,pspc6;
   int icf = 0, ndf = 0, config = 0;
   int cid = 0;
   char gtype[2] = "G\0";

   struct node *p;

   n1=n2=n3=n4=n5=0;
   pspc1=pspc2=pspc3=pspc4=pspc5=pspc6=0;

   for ( p = *start; (p->next) != NULL; p = (p->next) )
   {
      ++id;
      fprintf(output_file,"%2d%8d%8d%8d%8d%8d%8d%8d%8d\n",
             ipkt,id,iv,kc,n1,n2,n3,n4,n5);
      fprintf(output_file,"%16.9f%16.9f%16.9f\n",p->x,p->y,p->z);
      fprintf(output_file,"%1d%1s%8d%8d%8d  %1d%1d%1d%1d%1d%1d\n",
             icf,gtype,ndf,config,cid,
              pspc1,pspc2,pspc3,pspc4,pspc5,pspc6);
   }


   return 0;
}

/*---------------------------------------------------------------------------------*/

int wrt_elements(struct element **start_el)
{
   int ipkt=2;
   int i,id,iv=3,kc=2;
   int n1,n2,n3,n4,n5;
   int nodes=3, config=0, pid=0, ceid=0;
   float theta1=0.0,theta2=0.0,theta3=0.0;

   struct element *p;

   n1=n2=n3=n4=n5=0;
   id = 0;

   for ( p = *start_el; (p->next) != NULL; p = (p->next) )
   {
      ++id;
      fprintf(output_file,"%2d%8d%8d%8d%8d%8d%8d%8d%8d\n",
             ipkt,id,iv,kc,n1,n2,n3,n4,n5);
      fprintf(output_file,"%8d%8d%8d%8d%16.9f%16.9f%16.9f\n",
             nodes,config,pid,ceid,theta1,theta2,theta3);
      fprintf(output_file,"%8d%8d%8d \n",
                  p->ielm0,p->ielm1,p->ielm2);
   }


   return 0;
}


/*---------------------------------------------------------------------------------*/

void create_node(float x, float y, float z)
{
   struct node *new;

   new = (struct node *)malloc (sizeof(example));
   if (new == NULL)
   {
      printf("\n Out of Memory for node linked list");
      exit(1);
   }

   new->x = x;
   new->y = y;
   new->z = z;

   sl_store(new, &start, &last);
}

/*---------------------------------------------------------------------------------*/

void sl_store(struct node *i, struct node **start, struct node **last)
{

   if ( *last == NULL )
   {
      *last = i;
      *start = i;
   }
   else
   {
      (*last)->next = i;
   }

/* Set component - next */
   i->next = NULL;

/* Reset address *last ready for next struct */
   *last = i;
}

/*---------------------------------------------------------------------------------*/

void create_element(int ielm0, int ielm1, int ielm2)
{
   struct element *new;

   new = (struct element *)malloc (sizeof(example2));
   if (new == NULL)
   {
      printf("\n Out of Memory for element linked list");
      exit(1);
   }

   new->ielm0 = ielm0;
   new->ielm1 = ielm1;
   new->ielm2 = ielm2;

   sl_store_el(new, &start_el, &last_el);
}

/*---------------------------------------------------------------------------------*/

void sl_store_el(struct element *i,struct element **start_el,struct element **last_el)
{

   if ( *last_el == NULL )
   {
      *last_el = i;
      *start_el = i;
   }
   else
   {
      (*last_el)->next = i;
   }

/* Set component - next */
   i->next = NULL;

/* Reset address *last_el ready for next struct */
   *last_el = i;
}

/*---------------------------------------------------------------------------------*/

main(int argc, char * argv[])
{
   int il, j, len_line;
   extern char line[];
   extern char word[];
   int irec = 0;
   int iret = 0;
   int ip, diff;
   char name[6];
   int ielm[3];
   float x, y, z;

   int ctr,n;
   char *arg1=NULL;
   char *arg2=NULL;
   char *arg3=NULL;
   char *arg4=NULL;
   char file_in[81];
   char file_out[81];

   char *usgmsg[] = {
        "Usage: stl2pat -input file_in -output file_out",
        "where:",
        "    file_in  = stl filename ",
        "    file_out = output filename ",
        " eg. stl2pat -input unit_cube.stl -output unit_cube.out ",
        NULL
        };

   start = last = NULL;
   start_el = last_el = NULL;

/* Look at the arguments given on the command line */

/*   for (ctr = 0; ctr < argc; ctr++)
   {
      printf("argument #%d is -> |%s|\n", ctr, argv[ctr]);

   }  */

   if (argc>0)
      arg1 = argv[1];
   if (argc>1)
      arg2 = argv[2];
   if (argc>2)
      arg3 = argv[3];
   if (argc>3)
      arg4 = argv[4];

   if (argc != 5)
   {
      for (n = 0; usgmsg[n] != NULL; n++)
            printf ("%s\n", usgmsg[n]);
        exit (0);
   }

   if (arg1 && (strcmp(arg1,"-input") == 0))
   {
      if (arg2)
      {
         strcpy(file_in,arg2);
      }
   }
   else
      {
      for (n = 0; usgmsg[n] != NULL; n++)
            printf ("%s\n", usgmsg[n]);
        exit (0);
   }

   if (arg3 && (strcmp(arg3,"-output") == 0))
   {
      if (arg4)
      {
         strcpy(file_out,arg4);
      }
   }
   else
   {
      for (n = 0; usgmsg[n] != NULL; n++)
            printf ("%s\n", usgmsg[n]);
        exit (0);
   }

/* Open input and output files */
   input_file = fopen(file_in,"r");

/* check if input file exists */
   if (input_file == NULL)
   {
      printf("Could not open input file\n");
      exit(0);
   }

/* check if output file exists */
   output_file = fopen(file_out,"w");
   if (output_file == NULL)
   {
      printf("Could not open output file\n");
      exit(0);
   }


                /* read first line and word */
    len_line = getline();
    getword();

/* Check that first line of stl file starts with the
   word solid */

    diff = strcmp(word,"solid");
    if ( diff != 0 ) 
    {
       printf("First line of stl file not recognised");
       exit(0);
    }


     /* Each record has 7 lines
-----------------------------------------------------------
|               facet normal ....   ....   ....           |
|                  outer loop                             |
|                     vertex ....   ....   ....           |
|                     vertex ....   ....   ....           |
|                     vertex ....   ....   ....           |
|                  endloop                                |
|               endfacet                                  |
-----------------------------------------------------------
                                 */

/* Read first line of first record */
    getline();
    getword();

/* Read records */

    while ( strcmp(word,"facet") == 0 )
    {

 /* start new record */
       ++irec;

/* read second line of record */
       getline();
       getword();

       diff = strcmp(word,"outer");
       if ( diff != 0 ) 
       {
          printf("Second line of record not recognised \n");
          exit(0);
       }

/* read third, fourth and fifth lines of record */

       for (il = 1; il < 4; ++il)
       {

/* ip counts the number of nodes */
          ip = 3*irec - 3 + il;

          ielm[il-1] = ip;

          getline();
          getword();
          diff = strcmp(word,"vertex");
          if ( diff != 0 ) 
          {
             printf("line of record not recognised \n");
             printf("Line %s \n",line);
             printf("Record number %d \n",irec);
             exit(0);
          }

/* read line containing x,y,z */
          sscanf(line,"%s %f %f %f", name, &x, &y, &z);

/* create structure node which has components:
                x,
                y,
                z,
                next                   */

          create_node(x,y,z);
          
       }
       create_element(ielm[0],ielm[1],ielm[2]);

/* read sixth line of record */
       getline();
       getword();

       diff = strcmp(word,"endloop");
       if ( diff != 0 ) 
       {
          printf("Sixth line of record not recognised");
          printf("Line %s \n",line);
          printf("Record number %d \n",irec);
          exit(0);
       }

/* read seventh line of record */
       getline();
       getword();

       diff = strcmp(word,"endfacet");
       if ( diff != 0 ) 
       {
          printf("Seventh line of record not recognised");
          printf("Line %s \n",line);
          printf("Record number %d \n",irec);
          exit(0);
       }

/* read next line - either first line of next record
                    or last line of file  */
       getline();
       getword();

   }

   if ( (diff = strcmp(word,"endsolid")) != 0 )
   {
      printf("Word at start of line not recognised");
      printf("Line %s \n",line);
      printf("Last record number read was %d \n",irec);
      exit(0);
   }

/* Write out Patran file */

   iret =  wrt_title_card();
   if (iret != 0 ) 
   {
      printf("Error writing title card to output_file");
   }

   iret = wrt_summary(ip,irec);
   if (iret != 0 ) 
   {
      printf("Error writing summary to output_file");
   }

   iret = wrt_nodes(&start);
   if (iret != 0 ) 
   {
      printf("Error writing nodes to output_file");
   }

   iret = wrt_elements(&start_el);
   if (iret != 0 ) 
   {
      printf("Error writing elements to output_file");
   }




/* close the input and output files */
fclose(input_file);
fclose(output_file);

}

/*---------------------------------------------------------------------------------*/



