/***************************************************************/
/*               Diagrammgenerator fuer LaTeX                  */
/*                  (C) 1996 Reinhard Rapp                     */
/***************************************************************/

#include <stdio.h>

#define xyarsize 5000 /* max. Anzahl X/Y-Koordinatenpaare      */
#define maxticks 200  /* max. Anzahl Achsenbeschriftungspunkte */

char *infilename = "diagdata.txt";    /* Eingabedatei (Daten)  */
char *outfilename = "diagram.tex";    /* Ausgabedatei (LaTeX)  */

float totalwidth = 155.0;             /* Gesamtabmessungen     */
float totalheight = 100.0;
float leftmargin = 20.0;              /* Raender ausserhalb    */
float rightmargin = 10.0;             /* der Koordinatenachsen */
float topmargin = 10.0;
float bottommargin = 10.0;
float curveleftmargin = 5.0;          /* Raender innerhalb     */
float curverightmargin = 5.0;         /* der Koordinatenachsen */
float curvebottommargin = 5.0;
float curvetopmargin = 5.0;
float ticklength = 1.0;               /* Achsenmarkierungen    */

/* Daten fuer Diagramm und Achsenbeschriftung laden */
loadinputs(xtick, noxticks, ytick, noyticks, xmin, xmax, 
   ymin, ymax, xar, yar, nopairs)
   float xtick[maxticks];
   long *noxticks;
   float ytick[maxticks]; 
   long *noyticks;
   float *xmin, *xmax, *ymin, *ymax;
   float xar[xyarsize];
   float yar[xyarsize];
   long *nopairs;   
{
   FILE *infil;
   char instr[500];
   long i;
   int mode;
   int xtoggle;
   if ((infil=fopen(infilename,"r"))==NULL) {
      fprintf(stderr,"%s: Datei nicht gefunden.\n", infilename);
      exit(-1);
   }
   xtoggle = 1;
   *noxticks = 0;
   *noyticks = 0;
   *nopairs = 0;
   mode = 0;
   do { 
      fscanf(infil,"%s", instr);
      for(i = 0; i < strlen(instr); i++) instr[i] = tolower(instr[i]);
      if(!feof(infil)) {
         if((instr[0] == 'x') || (instr[0] == 'y')) {
            if(!strcmp(instr, "xmark")) mode = 1;
            if(!strcmp(instr, "ymark")) mode = 2;
            if(!strcmp(instr, "xmin")) mode = 3;
            if(!strcmp(instr, "xmax")) mode = 4;
            if(!strcmp(instr, "ymin")) mode = 5;
            if(!strcmp(instr, "ymax")) mode = 6;
         }
         else {
            switch(mode) {
               case 1: sscanf(instr, "%f", &xtick[*noxticks]);
                       (*noxticks)++; break;
               case 2: sscanf(instr, "%f", &ytick[*noyticks]);
                       (*noyticks)++; break;
               case 3: sscanf(instr, "%f", xmin); mode = 7; break;
               case 4: sscanf(instr, "%f", xmax); mode = 7; break;
               case 5: sscanf(instr, "%f", ymin); mode = 7; break;
               case 6: sscanf(instr, "%f", ymax); mode = 7; break;
               case 7: if(xtoggle) sscanf(instr, "%f", &xar[*nopairs]);
                       else { 
                          sscanf(instr, "%f", &yar[*nopairs]);
                          (*nopairs)++;
                       }
                       xtoggle = !xtoggle;
                       break;
            }
         }
      }
   } while(!feof(infil));
   fclose(infil);
}

/* Bestimmung des Minimums und des Maximums in einem Array */
getminmax(xar, nodata, xmin, xmax)
   float xar[xyarsize];
   long nodata;
   float *xmin;
   float *xmax;
{
   long i;
   *xmin = 1.0e+30;
   *xmax = 1.0e-30;
   for(i = 0; i < nodata; i++) {
      if(xar[i] < *xmin) *xmin = xar[i];
      if(xar[i] > *xmax) *xmax = xar[i];
   } 
}

/* Koordinatentransformation fuer X-Werte */
float transformx(xact, xmin, xmax)
   float xact;
   float xmin;
   float xmax;
{
   float curvewidth;
   float newx;
   curvewidth = totalwidth - leftmargin - rightmargin 
      - curveleftmargin - curverightmargin;
   newx = ((xact - xmin) * curvewidth) / (xmax - xmin) 
      + leftmargin + curveleftmargin;
   return(newx);
}

/* Koordinatentransformation fuer Y-Werte */
float transformy(yact, ymin, ymax)
   float yact;
   float ymin;
   float ymax;
{
   float newx;
   float curveheight;
   curveheight = totalheight - topmargin - bottommargin 
      - curvebottommargin - curvetopmargin;
   newx = ((yact - ymin) * curveheight) / (ymax - ymin) 
      + bottommargin + curvebottommargin;
   return(newx);
}

/* Generierung eines Punkt-, Linien- oder Balkendiagrammes */
diagram(mode)
   char mode;
{
   FILE *outfil;
   float xar[xyarsize], yar[xyarsize];
   float xtick[maxticks], ytick[maxticks];
   long noxticks, noyticks;
   long noxypairs;
   float xmin, xmax, ymin, ymax;
   float datamin, datamax;
   float arg1, arg2, arg3, arg4, arg5;
   float barwidth;
   float storval;
   long i;

   loadinputs(xtick, &noxticks, ytick, &noyticks, &xmin, &xmax, 
      &ymin, &ymax, xar, yar, &noxypairs);
   printf("\nEINGABEKONTROLLE\n\nxmark ");
   for(i = 0; i < noxticks; i++) printf("%g ", xtick[i]);
   printf("\nymark ");
   for(i = 0; i < noyticks; i++) printf("%g ", ytick[i]);
   printf("\nxmin  %g\nxmax  %g\n", xmin, xmax);
   printf("ymin  %g\nymax  %g\n", ymin, ymax);
   for(i = 0; i < noxypairs; i++) printf("%g   %g\n", xar[i], yar[i]);
   printf("\nMINIMA UND MAXIMA DER KOORDINATENPAARE\n\n");
   getminmax(xar, noxypairs, &datamin, &datamax);
   printf("Minimales X: %10g      Maximales X: %10g\n", datamin, datamax);
   getminmax(yar, noxypairs, &datamin, &datamax);
   printf("Minimales Y: %10g      Maximales Y: %10g\n", datamin, datamax);
   if (mode == 'b') {
      xmin = xmin - 0.5; /* Balkenbreite beruecksichtigen */
      xmax = xmax + 0.5;
   }

   storval = curvebottommargin;
   if (mode == 'b') curvebottommargin = 0.0;

   if ((outfil=fopen(outfilename,"w"))==NULL) {
      fprintf(stderr,"%s: Fehler beim Anlegen der Datei.\n", outfilename);
      exit(-1);
   }

   if (mode == 'l') fprintf(outfil, "\\documentstyle[12pt,epic]{article}\n");
   else fprintf(outfil, "\\documentstyle[12pt]{article}\n");

   fprintf(outfil, "\\textwidth15.5cm\n");
   fprintf(outfil, "\\textheight23cm\n");
   fprintf(outfil, "\\begin{document}\n");
   fprintf(outfil, "\\begin{figure}\n");
   fprintf(outfil, "\\begin{center}\n");
   fprintf(outfil, "\\unitlength1mm\n");      
   fprintf(outfil, "\\begin{picture}(%.2f,%.2f)\n", totalwidth, 
      totalheight);

   fprintf(outfil, "%% ***** Rahmen\n");
   fprintf(outfil, "\\put(0,0){\\framebox(%.2f, %.2f)}\n", 
      totalwidth, totalheight);

   fprintf(outfil, "%% ***** X-Achse\n");
   arg1 = leftmargin;
   arg2 = bottommargin;
   arg3 = totalwidth - rightmargin - leftmargin;
   fprintf(outfil, "\\put(%.2f,%.2f){\\vector(1,0){%.2f}}\n", arg1, 
      arg2, arg3);
   arg1 = totalwidth - rightmargin + ticklength + ticklength;
   fprintf(outfil, "\\put(%.2f,%.2f){\\makebox(0,0)[l]{X}}\n",
      arg1, arg2);
   for(i = 0; i < noxticks; i++) {
      arg1 = transformx(xtick[i], xmin, xmax);
      arg2 = bottommargin;
      arg3 = ticklength;
      fprintf(outfil, "\\put(%.2f,%.2f){\\line(0,-1){%.2f}}\n", 
         arg1, arg2, arg3);
      arg2 = bottommargin - ticklength - ticklength - ticklength;
      arg3 = xtick[i];
      fprintf(outfil, "\\put(%.2f,%.2f){\\makebox(0,0)[t]{%g}}\n",
         arg1, arg2, arg3);
   }

   fprintf(outfil, "%% ***** Y-Achse\n");
   arg1 = leftmargin;
   arg2 = bottommargin;
   arg3 = totalheight - bottommargin - topmargin;
   fprintf(outfil, "\\put(%.2f,%.2f){\\vector(0,1){%.2f}}\n", arg1, 
      arg2, arg3);
   arg2 = totalheight - topmargin + ticklength + ticklength;
   fprintf(outfil, "\\put(%.2f,%.2f){\\makebox(0,0)[b]{Y}}\n",
      arg1, arg2);
   for(i = 0; i < noyticks; i++) {
      arg1 = leftmargin;
      arg2 = transformy(ytick[i], ymin, ymax);
      arg3 = ticklength;
      fprintf(outfil, "\\put(%.2f,%.2f){\\line(-1,0){%.2f}}\n", 
         arg1, arg2, arg3);
      
      arg1 = leftmargin - ticklength - ticklength - ticklength;
      arg3 = ytick[i];
      fprintf(outfil, "\\put(%.2f,%.2f){\\makebox(0,0)[r]{%g}}\n",
         arg1, arg2, arg3);
   }
   fprintf(outfil, "%% ***** Daten\n");

   if(mode == 'p') {                        /* Punktdiagramm */
      for(i = 0; i < noxypairs; i++) {
         arg1 = transformx(xar[i], xmin, xmax);
         arg2 = transformy(yar[i], ymin, ymax);
         fprintf(outfil, "\\put(%.2f,%.2f){\\circle*{1.2}}\n", 
            arg1, arg2);
      }
   }

   if(mode == 'b') {                        /* Balkendiagramm */
      barwidth = transformx(2.0, xmin, xmax) - transformx(1.0, xmin, xmax);
      for(i = 0; i < noxypairs; i++) {
         arg1 = transformx(xar[i] - 0.5, xmin, xmax);
         arg2 = transformx(xar[i] + 0.5, xmin, xmax);
         arg3 = bottommargin + curvebottommargin;
         arg4 = transformy(yar[i], ymin, ymax);
         arg5 = arg4 - bottommargin - curvebottommargin;
         fprintf(outfil, "\\put(%.2f,%.2f){\\line(0,1){%.2f}}\n",
            arg1, arg3, arg5); /* linker Balkenstrich */
         fprintf(outfil, "\\put(%.2f,%.2f){\\line(0,1){%.2f}}\n",
            arg2, arg3, arg5); /* rechter Balkenstrich */
         fprintf(outfil, "\\put(%.2f,%.2f){\\line(1,0){%.2f}}\n",
            arg1, arg4, barwidth); /* Querstrich */
      }
   }

   if(mode == 'l') {                        /* Liniendiagramm */
      fprintf(outfil, "\\drawline");
      for(i = 0; i < noxypairs; i++) {
         arg1 = transformx(xar[i], xmin, xmax);
         arg2 = transformy(yar[i], ymin, ymax);
         fprintf(outfil, "(%.2f,%.2f)", arg1, arg2);
      }
      fprintf(outfil, "\n");
   }

   fprintf(outfil, "\\end{picture}\n"); 
   fprintf(outfil, "\\end{center}\n");
   fprintf(outfil, "\\vspace{-0.4cm}\n");
   fprintf(outfil, "\\caption{BESCHREIBUNG}\n");
   fprintf(outfil, "\\label{LABEL}\n");
   fprintf(outfil, "\\end{figure}\n");
   fprintf(outfil, "\\end{document}\n");

   fclose(outfil);
   curvebottommargin = storval;
}

main()
{
   char inchar;
   int quit = 0;
   inchar = ' ';
   while (!quit) { 
      printf("\n+---------------------------------------+\n");
      printf("|      Diagrammgenerator fuer LaTeX     |\n");
      printf("+---------------------------------------+\n\n");
      printf("Eingabedaten:    %s\n", infilename); 
      printf("LaTEX-Diagramm:  %s\n", outfilename); 
      printf("\n");
      printf("<A> Punkt-Diagramm\n");
      printf("<B> Balken-Diagramm\n");
      printf("<C> Linien-Diagramm (benoetigt epic.sty)\n");
      printf("<Q> quit\n\n");
      printf("Kommando: ");
      fflush(stdout);    
      inchar = getchar();
      while(inchar == 10) inchar = getchar();
      switch(inchar) {
         case 'a': diagram('p'); break;
         case 'b': diagram('b'); break;
         case 'c': diagram('l'); break;
         case 'q': quit = 1; break;
         default:  printf("Falsche Eingabe: %d\n\n", (int)inchar);
      }
   }
}

