/***************************************************************************
*                    Copyright (c) 1986, Tim Mooney                        *
*                                                                          *
*      This software is released into the public domain.  You may use,     *
*   copy, modify, and redistribute it if this notice is retained.  You     *
*   may not sell it, but you may charge a nominal copying/hassle fee for   *
*   making it available.                                                   *
*                                                                          *
*      MP is not finished.  Send comments, suggestions, etc. to            *
*                                                                          *
*                                            Tim Mooney                    *
*                                            120 Purefoy Rd.               *
*                                            Chapel Hill NC  27514         *
***************************************************************************/

/***************************************************************************
*   mp.c - PLOT DATA EMBEDDED IN TEXT FILE
*
*      Mp reads a text file and extracts data from it in a user-defined way.
*   (See getdat.c for details.  Also, interactive help is available.)
*   When the data are collected, mp opens a high-res screen, and plots some
*   or all of the data -- again, in a user-defined way.  Some of the
*   details of plotting specifications (keywords: "how_to string") are
*   explained in the file sample.dat.  Interactive help is also available
*   from the function GetHowTo().
****************************************************************************
*   Capabilities, limitations, and implementation notes:
*
*      Mp can plot lines or points of varying sizes; with or without error
*   bars; in 10 colors.  There is no internal limit on the number of data
*   sets plotted simultaneously, or on the number of points in a single
*   data set, or on the total size of all data sets.  Memory is allocated
*   dynamically; when it's used up, mp will stop processing the data file
*   and crash when it tries to open a new screen.
*
*      Points are actually drawn as squares, except for the smallest sizes.
*   Mp doesn't plot any other kinds of marks.  Points may be any size; one
*   may fill the screen, in fact.  All lines are solid, error bars are
*   lines.
*
*      GetDat() can scale data on input, directed by information in the
*   data file it's reading.  Although GetDat() can also extract a title and
*   labels from the data file, mp makes no use of them at present.  
*
*      Once the data are plotted on the screen, the user can zoom in and
*   out, disable axes and grid, etc.  Also, the current picture can be
*   dumped to a file for plotting.  The only plotter language supported
*   is HPGL (Hewlett-Packard) since it's the only one I know.
*
*      Fast Floating Point routines are used throughout.
***************************************************************************/

#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include "struct.h"
#include "plotlim.h"

extern int GetDat();
extern void plot();

long GfxBase = 0;
long IntuitionBase = 0;
int debug = FALSE;

FFP xtic[MAXTICS],ytic[MAXTICS];
short xticp[MAXTICS],yticp[MAXTICS];
char filename[30];

main(argc,argv)
char *argv[];
int argc;
{

   register short i, j;
   int help=FALSE;
   int xcol=1, ycol=2, ecol=0, terse=TRUE;
   char c;
   FILE *fp;
   struct Pict *Pict;

   /*** PARSE ARGS ***/
   filename[0] = 0;
   for (i=1; i<argc; i++) {
      if (argv[i][0] == '-') {
         j=1;
         while (c = argv[i][j++]) {
            switch (c) {
               case 'd':   debug = TRUE; break;
               case 'h':   help = TRUE; break;
               case 'v':   terse = FALSE; break;
               case 'x':
                  xcol = isdigit(argv[i][j]) ? atoi(&argv[i][j++]) : 0;
                  ycol=xcol+1;
                  break;
               case 'y':
                  ycol = isdigit(argv[i][j]) ? atoi(&argv[i][j++]) : xcol+1;
                  break;
               case 'e':
                  ecol = isdigit(argv[i][j]) ? atoi(&argv[i][j++]) : ycol+1;
                  break;
            }
         }
      }
      else if (argv[i][0] == '?')
         help = TRUE;
      else
         strcpy(filename,argv[i]);
   }

   if (help || !(*filename)) {
      printf("usage: \x9b2mmp\x9bm [\x9b2m-x\x9bm[\x9b2m#\x9bm]\x9b2my\x9bm[\x9b2m#\x9bm]\x9b2me\x9bm[\x9b2m#\x9bm]\x9b2mvd\x9bm]\x9b2m filename\x9bm\n");
      printf("   \x9b2m-x\x9bm[\x9b2m#\x9bm] x in col # (if 0, no x) default:1\n");
      printf("   \x9b2m-y\x9bm[\x9b2m#\x9bm] y in col # (err if #=0) default:x_col+1\n");
      printf("   \x9b2m-e\x9bm[\x9b2m#\x9bm] e in col # (if 0, no e) default:0 (no \x9b2me\x9bm); x_col+2 (\x9b2me\x9bm but no \x9b2m#\x9bm)\n");
      printf("   \x9b2m-v\x9bm    verbose file inspection default:terse\n");
      printf("   \x9b2m-d\x9bm    debug on                default:off\n");
      printf("\nEXAMPLE: mp -x0y1e2 mydatafile.dat\n");
      printf("   for a file containing y data in column 1, err_in_y data\n");
      printf("   in column 2, and no x data. (relative line # used for x)\n");
      exit(0);
   }
   

   /*** OPEN LIBRARIES ***/
   FFPLARGE = 1.0e10; FFPSMALL = 1.0e-10;
   
   GfxBase = OpenLibrary("graphics.library",0);
   if(GfxBase == NULL) {
      printf("Can't open graphics library...\n");
      exit(1);
   }
   IntuitionBase = OpenLibrary("intuition.library",0);
   if(IntuitionBase == NULL) {
      printf("Can't open intuition library...\n");
      exit(1);
   }

   /*** OPEN FILE ***/
   fp = fopen(filename,"r");
   if (!fp) {
      printf("can't open %s\n",filename);
      exit(1);
   }

   /*** ALLOCATE/INITIALIZE MEMORY FOR struct Pict ***/
   Pict = (struct Pict *)AllocMem(sizeof(struct Pict),MEMF_CLEAR);
   Pict->ErrBar = (ecol != 0);
   Pict->Tics = (struct Tics *)AllocMem(sizeof(struct Tics),MEMF_CLEAR);
   Pict->Tics->x = xtic;Pict->Tics->y = ytic;
   Pict->Tics->xp = xticp;Pict->Tics->yp = yticp;
   Pict->XRegionLock = Pict->YRegionLock = FALSE;
   Pict->Axes = TRUE;
   Pict->CurrReg =
      (struct PlotRegion *)AllocMem(sizeof(struct PlotRegion),MEMF_CLEAR);
   Pict->NewReg =
      (struct PlotRegion *)AllocMem(sizeof(struct PlotRegion),MEMF_CLEAR);
   Pict->Title = NULL;
   Pict->XLabel = NULL;
   Pict->YLabel = NULL;
   Pict->Plot = NULL;

   /*** GET DATA FROM FILE ***/
   GetDat(fp, xcol, ycol, ecol, terse, Pict);
   if (debug) printf("mp: closing data file\n");
   (void) fclose(fp);


   /*** PLOT DATA ***/
   plot(Pict);

   /*** DEALLOCATE MEMORY ***/
   FreeMem(Pict->NewReg,sizeof(struct PlotRegion));
   FreeMem(Pict->CurrReg,sizeof(struct PlotRegion));
   FreeMem(Pict->Tics,sizeof(struct Tics));
   FreeMem(Pict,sizeof(struct Pict));
   FreeStructPlot();
   return(0);
}

/************************************************/
#define P_XREG 10000
#define P_YREG 10000
#define P_X_TIC_SIZE X_TIC_SIZE*(P_YREG/MAXVERT)
#define P_Y_TIC_SIZE Y_TIC_SIZE*(P_XREG/MAXHORIZ)
#define P_CH_WID 75
#define P_CH_HEI 150
#define P_LMARGIN P_CH_WID*8
#define P_BMARGIN P_CH_HEI*2
#define P_TMARGIN 0
#define P_RMARGIN 0

static FFP XScale, YScale, XOffset, YOffset;

void fWrtFFP(fp, ffpval)
FILE *fp;
FFP ffpval;
{
   fprintf(fp, "%d", (int)ffpval);
}


void WrtAxes(fp, Tics, Grid)
FILE *fp;
struct Tics *Tics;
short Grid;
{
   short n, tmpx, tmpy, i;
   FFP *x, *y;
   char tmpstr[20];
      
   /*** DRAW BORDER ***/
   fprintf(fp,"SP1;PU%d %d;",P_LMARGIN,P_BMARGIN);
   fprintf(fp,"PD%d %d %d %d %d %d %d %d;\n",P_XREG,P_BMARGIN,P_XREG,P_YREG,
   P_LMARGIN,P_YREG,P_LMARGIN,P_BMARGIN);

   /*** DRAW TICS/GRID ***/
   fprintf(fp,"SP2;");
   x=Tics->x; y=Tics->y;
   for (i=1; i < Tics->NX; i++) {
      if (Grid) {
         fprintf(fp,"PU"); fWrtFFP(fp,(XScale * (XOffset + x[i])));
         fprintf(fp," %d;PD",P_BMARGIN);
         fWrtFFP(fp,(XScale * (XOffset + x[i])));
         fprintf(fp," %d;\n",P_YREG);
      }
      else {
         fprintf(fp,"PU"); fWrtFFP(fp,(XScale * (XOffset + x[i])));
         fprintf(fp," %d;PD",P_BMARGIN);
         fWrtFFP(fp,(XScale * (XOffset + x[i])));
         fprintf(fp," %d;",P_BMARGIN + P_X_TIC_SIZE);
         fprintf(fp,"PU"); fWrtFFP(fp,(XScale * (XOffset + x[i])));
         fprintf(fp," %d;PD",P_YREG);
         fWrtFFP(fp,(XScale * (XOffset + x[i])));
         fprintf(fp," %d;\n",P_YREG - P_X_TIC_SIZE);
      }
   }
   for (i=1; i < Tics->NY; i++) {
      if (Grid) {
         fprintf(fp,"PU%d ",P_LMARGIN);
         fWrtFFP(fp,(YScale * (YOffset + y[i])));
         fprintf(fp,"PD%d ",P_XREG);
         fWrtFFP(fp,(YScale * (YOffset + y[i])));
         fprintf(fp,";\n");
      }
      else {
         fprintf(fp,"PU%d ",P_LMARGIN);
         fWrtFFP(fp,(YScale * (YOffset + y[i])));
         fprintf(fp,";PD%d ", P_LMARGIN + P_Y_TIC_SIZE);
         fWrtFFP(fp,(YScale * (YOffset + y[i])));
         fprintf(fp,";");
         fprintf(fp,"PU%d ",P_XREG);
         fWrtFFP(fp,(YScale * (YOffset + y[i])));
         fprintf(fp,";PD%d ", P_XREG - P_Y_TIC_SIZE);
         fWrtFFP(fp,(YScale * (YOffset + y[i])));
         fprintf(fp,";\n");
      }
   }

   /*** PRINT TIC VALUES ***/
   fprintf(fp,"SP1;");
   for (i=0; i < Tics->NX; i++) {
      n = sprintf(tmpstr, "%-.4f", Tics->x[i]);
      n = min(n, 7);
      while (tmpstr[n-1] == '0') n--;
      tmpstr[n]=0;
      tmpx = (short)((XScale * (XOffset + Tics->x[i])));
      tmpx -= (((n+1)/2)-.5) * P_CH_WID;
      fprintf(fp, "PU%d 1;", tmpx);
      fprintf(fp,"LB%s\003", tmpstr);
   }
   for (i=0; i < Tics->NY; i++) {
      n = sprintf(tmpstr, "%-.4f", Tics->y[i]);
      n = min(n, 7);
      while (tmpstr[n-1] == '0') n--;
      tmpstr[n]=0;
      tmpy = (short)((YScale * (YOffset + Tics->y[i])));
      tmpy -= .5 * P_CH_WID;
      fprintf(fp, "PU1 %d;", tmpy);
      fprintf(fp,"LB%s\003", tmpstr);
   }
}


extern char *stpchr();

WrtPlt(Pict)
struct Pict *Pict;
{
   FILE *fp;
   short i;
   struct Plot *Plot;
   FFP *x, *y, *e;
   short xptsiz, yptsiz;
   char plotname[30], *chptr;
   static char PlotNum = 0;

   strcpy(plotname,filename);
   if (chptr = stpchr(plotname,'.')) {
      chptr[1]='p'; chptr[2]='l'; chptr[3]='t';
      chptr[4] = '0' + PlotNum; chptr[5]=0;
   }
   else {
      i=strlen(plotname); plotname[i]='.';
      plotname[i+1]='p'; plotname[i+2]='l'; plotname[i+3]='t';
      plotname[i+4] = '0' + PlotNum; plotname[i+5]=0;
   }
   
   if (!(fp = fopen(plotname,"w") ))
      {printf("can't open %s\n",plotname); return(FALSE);}

   fprintf(fp,"IN;SC 0 %d 0 %d;\n", P_XREG+2, P_YREG+2);
   fprintf(fp,"VS 20.0;\n");  /* VELOCITY cm/s */
   fprintf(fp,"\033.N;19:\033.I81;;17:\n"); /* XON/XOFF */
   XScale = (FFP)(P_XREG - P_LMARGIN - P_RMARGIN) /
            (Pict->CurrReg->XMax - Pict->CurrReg->XMin);
   YScale = (FFP)(P_YREG - P_BMARGIN - P_TMARGIN) /
            (Pict->CurrReg->YMax - Pict->CurrReg->YMin);
   XOffset = (FFP)(P_LMARGIN) / XScale - Pict->CurrReg->XMin;
   YOffset = (FFP)(P_BMARGIN) / YScale - Pict->CurrReg->YMin;

   Plot = Pict->Plot;
   while (Plot) {
      if (Plot->Enabled) {
         fprintf(fp,"PU;SP%d;\n", 1+Plot->Color-PLOTCOLORBASE);

         /* PLOT LINES */
         if (Plot->PointSize <= 0) {
            x=Plot->x; y=Plot->y;
            fprintf(fp, "PU"); fWrtFFP(fp,(XScale * (XOffset + *x)));
            fprintf(fp," ");
            fWrtFFP(fp,(YScale * (YOffset + *y))); fprintf(fp,";");
            x++; y++;
            fprintf(fp, "PD");
            for (i=1; i<Plot->NPts; i++, x++, y++) {
               if (i>1) fprintf(fp, " ");
               fWrtFFP(fp,(XScale * (XOffset + *x)));
               fprintf(fp," ");
               fWrtFFP(fp,(YScale * (YOffset + *y)));
            }
            fprintf(fp,";\n");
         }

         /* PLOT POINTS */
         if (Plot->PointSize != 0) {
/*            xptsiz = abs(Plot->PointSize) * (P_XREG / (100 * 11));  */
/*            yptsiz = abs(Plot->PointSize) * (P_YREG / (100 * 8.5)); */
            xptsiz = abs(Plot->PointSize) * (P_XREG / 1100);
            yptsiz = abs(Plot->PointSize) * (P_YREG / 850);
            x=Plot->x; y=Plot->y;
            for (i=0; i<Plot->NPts; i++, x++, y++) {
               fprintf(fp,"PU");
               fWrtFFP(fp,(XScale * (XOffset + *x)));
               fprintf(fp," ");
               fWrtFFP(fp,(YScale * (YOffset + *y)));
               fprintf(fp,";");
               fprintf(fp,"PR%d %d;", -xptsiz/2, -yptsiz/2);
               fprintf(fp,"PD%d 0 0 %d %d 0 0 %d;PA;\n",
                     xptsiz, yptsiz, -xptsiz, -yptsiz);
            }
         }

         /* PLOT ERROR BARS */
         if (Pict->ShowErr) {
            x=Plot->x; y=Plot->y; e=Plot->e;
            for (i=0; i<Plot->NPts; i++, x++, y++, e++) {
               fprintf(fp,"PU");
               fWrtFFP(fp,(XScale * (XOffset + *x)));
               fprintf(fp," ");
               fWrtFFP(fp,(YScale * (YOffset + (*y - *e))));
               fprintf(fp,";PD");
               fWrtFFP(fp,(XScale * (XOffset + *x)));
               fprintf(fp," ");
               fWrtFFP(fp,(YScale * (YOffset + (*y + *e))));
               fprintf(fp,";\n");
            }
         }
      }
      Plot = Plot->NextPlot;
   }

   fprintf(fp,"SR%f %f;\n",
         (float)(100*P_CH_WID) / (P_XREG - P_LMARGIN - P_RMARGIN),
         (float)(100*P_CH_HEI) / (P_YREG - P_BMARGIN - P_TMARGIN));
   WrtAxes(fp, Pict->Tics, Pict->Grid);

   fprintf(fp, "SP;");
   (void) fclose(fp);
   PlotNum++;
   return(TRUE);
}


To_mCAD(Pict)
struct Pict *Pict;
{
   FILE *fp;
   short i;
   struct Plot *Plot;
   FFP *x, *y, *e, xtmp, ytmp, xtmp1, ytmp1;
   FFP xptsiz, yptsiz, XReg, YReg, XScale, XOffset;
   char plotname[30], *chptr;
   static char mPlotNum = 0;

   strcpy(plotname,filename);
   if (chptr = stpchr(plotname,'.')) {
      chptr[1]='c'; chptr[2]='a'; chptr[3]='d';
      chptr[4] = '0' + mPlotNum; chptr[5]=0;
   }
   else {
      i=strlen(plotname); plotname[i]='.';
      plotname[i+1]='c'; plotname[i+2]='a'; plotname[i+3]='d';
      plotname[i+4] = '0' + mPlotNum; plotname[i+5]=0;
   }
   
   if (!(fp = fopen(plotname,"w") ))
      {printf("can't open %s\n",plotname); return(FALSE);}

   XReg = Pict->CurrReg->XMax - Pict->CurrReg->XMin;
   YReg = Pict->CurrReg->YMax - Pict->CurrReg->YMin;
   XScale = YReg/XReg * 1.4434; XOffset = Pict->CurrReg->XMin;

   Plot = Pict->Plot;
   while (Plot) {
      if (Plot->Enabled) {

         /* PLOT LINES */
         if (Plot->PointSize <= 0) {
            x=Plot->x; y=Plot->y;
            for (i=1; i<Plot->NPts; i++, x++, y++) {
               xtmp = XScale * (*x - XOffset);
               fprintf(fp, "%f %f\n", xtmp, *y);
            }
            fprintf(fp,"*>\n*C %d\n\n", 1+Plot->Color-PLOTCOLORBASE);
         }

         /* PLOT POINTS */
         if (Plot->PointSize != 0) {
            xptsiz = abs(Plot->PointSize) * (XReg / 582.);
            xptsiz = XScale * xptsiz;
            yptsiz = abs(Plot->PointSize) * (YReg / 360.);
            x=Plot->x; y=Plot->y;
            for (i=0; i<Plot->NPts; i++, x++, y++) {
               xtmp = XScale * (*x - XOffset);
               xtmp -= xptsiz/2;
               ytmp = *y - yptsiz/2;
               fprintf(fp,"%f %f\n", xtmp, ytmp); xtmp += xptsiz;
               fprintf(fp,"%f %f\n", xtmp, ytmp); ytmp += yptsiz;
               fprintf(fp,"%f %f\n", xtmp, ytmp); xtmp -= xptsiz;
               fprintf(fp,"%f %f\n", xtmp, ytmp); ytmp -= yptsiz;
               fprintf(fp,"%f %f\n", xtmp, ytmp);
               fprintf(fp,"*>\n*C %d\n\n", 1+Plot->Color-PLOTCOLORBASE);
            }
         }

         /* PLOT ERROR BARS */
         if (Pict->ShowErr) {
            x=Plot->x; y=Plot->y; e=Plot->e;
            for (i=0; i<Plot->NPts; i++, x++, y++, e++) {
               xtmp = XScale * (*x - XOffset);
               ytmp = *y - *e;
               fprintf(fp,"%f %f\n", xtmp, ytmp);
               ytmp = *y + *e;
               fprintf(fp,"%f %f\n", xtmp, ytmp);
               fprintf(fp,"*>\n*C %d\n\n", 1+Plot->Color-PLOTCOLORBASE);
            }
         }
      }
      Plot = Plot->NextPlot;
   }

   /*** DRAW TICS/GRID ***/
   x = Pict->Tics->x; y = Pict->Tics->y;
   for (i=1; i < Pict->Tics->NX; i++) {
      xtmp = XScale * (x[i] - XOffset);
      if (Pict->Grid) {
         PToU(Pict, 0, YMINP, &xtmp, &ytmp);
         PToU(Pict, 0, YMAXP, &xtmp1, &ytmp1);
         fprintf(fp,"%f %f\n%f %f\n*>\n*C 2\n\n", xtmp, ytmp, xtmp, ytmp1);
      }
      else {
         PToU(Pict, 0, YMINP, &xtmp1, &ytmp);
         fprintf(fp,"%f %f\n", xtmp, ytmp);
         PToU(Pict, 0, YMINP+X_TIC_SIZE, &xtmp1, &ytmp1);
         fprintf(fp,"%f %f\n*>\n*C 3\n\n", xtmp, ytmp1);
         PToU(Pict, 0, YMAXP, &xtmp1, &ytmp);
         fprintf(fp,"%f %f\n", xtmp, ytmp);
         PToU(Pict, 0, YMAXP-X_TIC_SIZE, &xtmp1, &ytmp1);
         fprintf(fp,"%f %f\n*>\n*C 3\n\n", xtmp, ytmp1);
      }
   }
   for (i=1; i < Pict->Tics->NY; i++) {
      if (Pict->Grid) {
         PToU(Pict, XMINP, YMINP, &xtmp, &ytmp);
         xtmp = XScale * (xtmp - XOffset);
         PToU(Pict, XMAXP, YMAXP, &xtmp1, &ytmp1);
         xtmp1 = XScale * (xtmp1 - XOffset);
         fprintf(fp,"%f %f\n%f %f\n*>\n*C 2\n\n", xtmp, y[i], xtmp1, y[i]);
      }
      else {
         PToU(Pict, XMINP, 0, &xtmp, &ytmp);
         xtmp = XScale * (xtmp - XOffset);
         fprintf(fp,"%f %f\n", xtmp, y[i]);
         PToU(Pict, XMINP+Y_TIC_SIZE, 0, &xtmp1, &ytmp1);
         xtmp1 = XScale * (xtmp1 - XOffset);
         fprintf(fp,"%f %f\n*>\n*C 3\n\n", xtmp1, y[i]);
         PToU(Pict, XMAXP, 0, &xtmp, &ytmp);
         xtmp = XScale * (xtmp - XOffset);
         fprintf(fp,"%f %f\n", xtmp, y[i]);
         PToU(Pict, XMAXP-Y_TIC_SIZE, 0, &xtmp1, &ytmp1);
         xtmp1 = XScale * (xtmp1 - XOffset);
         fprintf(fp,"%f %f\n*>\n*C 3\n\n", xtmp1, y[i]);
      }
   }

   /*** PRINT TIC VALUES ***/
/*
*   for (i=0; i < Pict->Tics->NX; i++) {
*      n = sprintf(tmpstr, "%-.4f", Pict->Tics->x[i]);
*      n = min(n, 7);
*      while (tmpstr[n-1] == '0') n--;
*      tmpstr[n]=0;
*   }
*   for (i=0; i < Pict->Tics->NY; i++) {
*      n = sprintf(tmpstr, "%-.4f", Pict->Tics->y[i]);
*      n = min(n, 7);
*      while (tmpstr[n-1] == '0') n--;
*      tmpstr[n]=0;
*   }
*/

   /*** DRAW AXES ***/
   PToU(Pict, XMINP, YMINP, &xtmp, &ytmp);
   xtmp = XScale * (xtmp - XOffset);
   PToU(Pict, XMAXP, YMAXP, &xtmp1, &ytmp1);
   xtmp1 = XScale * (xtmp1 - XOffset);
   fprintf(fp, "%f %f\n", xtmp, ytmp);
   fprintf(fp, "%f %f\n", xtmp1, ytmp);
   fprintf(fp, "%f %f\n", xtmp1, ytmp1);
   fprintf(fp, "%f %f\n", xtmp, ytmp1);
   fprintf(fp, "%f %f\n", xtmp, ytmp);
   fprintf(fp,"*C 1\n\n");

   (void) fclose(fp);
   mPlotNum++;
   return(TRUE);
}
