/*===========================================================================
  Copyright (C) 1995-2005 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*
 * HEADER : plotv80.c      - Vers 3.6.001  - Jul 1992 -  F.Tribioli, L.Fini, OAA
 *                         - Vers 3.6.000  - Dic 1989 -  F.Tribioli, OAA
 *
 * Plot generator for Versatec V-80 printers
 *
 * Usage: plotv80 -h    To get the usage help message
 *
 * 910228 CG: exit(); -> exit(1); 
 051021		last modif

 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#ifdef VMS
#include <descrip.h>
#include <ssdef.h>
#include <iodef.h>

#endif

#include <versatec.h>

#define FALSE 0
#define TRUE  1

static unsigned rowlen=DEFWDTOTPOINTS/8;

static int nrows;                /* Number of rows in the bitmap         */

#ifdef VMS
static short channel;
#else
FILE *channel;
#endif

#ifndef VMS
static unsigned char myoutbuffer[BUFSIZ];
#endif

static unsigned char codeline[DEFWDTOTPOINTS*2+1];
                                 /* Array to hold encoded bit map line   */
static unsigned char * rowpt[MAXROWS];
                                 /* Array to hold pointers to beginning  */
                                 /* of rows                              */
static unsigned char * pixels;   /* Pointer to dynamically allocated     */
                                 /* space                                */

                                 /* Bit masks                            */
static unsigned char bmasks[]={0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};

FILE * infile,* outfile;

static int clip=FALSE;
static int wflag=FALSE;

static double wdfact = 1.0;
static double lnfact = 1.0;

static double wdscale;
static double lnscale;

static long lnoffset = 0;
static long wdoffset = 0;
static long stripguard = 0.0;
static char csave='!';

static long nlines;             /* Input file line counter                 */
static long outlines=0;         /* Output print line counter               */

static char * writemode = "w";

void printhelp()
 {
  printf("\n\n");
  printf("Plot generator for Versatec V-80 printers.");
  printf(" Vers. 3.5 - F. Tribioli, Dec 1989.\n\n");
  printf("Usage: versatec [?/-h] [-wf] [-lf] [-c] [input]\n\n");
  printf("where:  input  is the input file (see note below)");
  printf(" (default is stdin)\n");
  printf("        -wf    apply a scaling factor f along paper width\n");
  printf("        -lf    apply a scaling factor f along paper length\n");
  printf("        -c     select clipping mode when requested ");
  printf("width is larger than\n");
  printf("               available (default is rescaling mode)\n");
  printf("        -s     enable splitting of large plot when requested ");
  printf("width is larger\n");
  printf("               than available (default is rescaling mode). ");
  printf("Disable -c switch\n");
  printf("        -h/?   Print this help information\n\n");
  printf("NOTE: the plotting program must be feed with an ");
  printf("input file generated\n");
  printf("      by the AGL standard raster driver and then ");
  printf("sorted alphabetically\n");
  printf("      with any sorting utility. If the file is not sorted ");
  printf("the rasterizer\n");
  printf("      will fail.\n\n");
  printf("Copyright 1989 by F. Tribioli. This program may be freely ");
  printf("copied and used\n");
  printf("provided this copyright notice will remain attached to it.\n\n");
 }

void markpixel(wd,ln)
 double wd,ln;
 {
  long wdidx,wdrest,wd0,ln0;
  unsigned char *pt;

  wd0 = wd+0.5;
  ln0 = ln+0.5;

  wdidx = wd0 >> 3;
  wdrest = wd0 & 7;

  if(ln0>=nrows || ln0<0) return;
  if(wdidx<0 || wdidx>=rowlen) return;
  *(rowpt[ln0]+wdidx) |= bmasks[wdrest];
  wflag=TRUE;
 }
  
/*
 * routine : getspace. Allocates memory space for the bitmap and sets the
 *                     required variables
 */

int getspace(n_rows)                   /* return 0 on success                */
 long n_rows;                          /* number of character rows           */
 {

  long i, nbytes;

  if(n_rows > MAXROWS)
   {
    printf("Rasterizer error: Bitmap strip length too big\n");
    exit(1);
   }

  nbytes = rowlen * n_rows; 

  pixels = (unsigned char *)malloc((size_t)nbytes);
  if(pixels == NULL)
   {
    printf("Rasterizer error: Not enough memory for bitmap\n");
    exit(1);
   }

  for(i=0; i<nbytes; i++) 
   pixels[i] = 0;

  nrows = n_rows;
  lnoffset = 0;
  stripguard = nrows;
  
  for(i=0; i<n_rows; i++)                     /* Initialize row pointers   */
    rowpt[i] = pixels + (i * rowlen);
 }

/*
 * routine: writeout. Write on output disk file a compressed bitmap
 */

void writeout()             /* Writes all character rows */
 {
  int nout,ndone;
  register i,j;
  unsigned res,leng;
  unsigned char *pt;

  leng=VERSATECBUFSIZE;

  if(wflag)
   for(i=0; i<nrows; i++)
    {
     pt=rowpt[i];
     ndone=0;
     do
      {
#ifdef VMS
       if((res=SYS$QIOW(0,channel,(short)(IO$_WRITEVBLK|IO$M_PLOT),0,0,0,
		pt+ndone,leng,0,0,0,0))!=SS$_NORMAL)
        {
         printf("ERROR! Cannot write data to printer");
         exit(1);
        }
#else
       if((nout=fwrite(pt+ndone,1,VERSATECBUFSIZE,channel))!=VERSATECBUFSIZE)
        {
         printf("ERROR! Cannot write data to printer");
         exit(1);
        }
#endif
       ndone+=VERSATECBUFSIZE;
      }
     while(ndone<rowlen);

     for(j=0;j<rowlen;j++) *(pt++)=0;			/* Clear bitmap     */
    }
 }

  
/*
 * routine : rasterize. Set pixels along vector trace
 */

void rasterize(c,wd0,ln0,wd1,ln1,hwid,vwid)
 char c;                             /* strip identifier                    */
 double wd0,ln0,wd1,ln1;             /* line ending points coordinates      */
 double hwid;                        /* Half line width (horizontal)        */
 double vwid;                        /* Half line width (vertical)          */
 {
  double wd,ln,wdend,lnend;
  double dw,dl,m;

  wd0 *= wdscale;                     /* First convert coordinates into      */
  wd1 *= wdscale;                     /* Pixel positions                     */

  ln0 *= lnscale;
  ln1 *= lnscale;
                                     /* physical strip length (=nrows)       */
  while(c>csave) 
   {
     writeout();
     stripguard+=nrows;
     lnoffset-=nrows;
     csave++;
   }

  csave=c;                          /* save strip identifier                */

  ln1+=lnoffset;      /* shift coordinates to fit well in the current strip */
  ln0+=lnoffset;
  wd0+=wdoffset;
  wd1+=wdoffset;

  if( (wd0<0 && wd1<0) || (wd0>DEFWDTOTPOINTS && wd1>DEFWDTOTPOINTS) ) return;

  dw=wd1-wd0; dl=ln1-ln0;

  if( fabs(dw) >= fabs(dl) )
   {                                /* Stepping along paper width         */
    if(dw<0.0)
     {
      wd=wd1; ln=ln1;
      wdend  =wd0; lnend  =ln0;
      m = (dl/dw);
     }
    else
      if(dw>0.0)
       {
        wd=wd0; ln=ln0;
        wdend  =wd1; lnend  =ln1;
        m = (dl/dw);
       }
      else
       {
        wd=wd1; ln=ln1;
        wdend  =wd1; lnend  =ln1;
        m=0.0;
        }

    while(wd<=wdend)
     {
      double lna=ln-vwid,lnb=ln+vwid,lnt;
      for(lnt=lna; lnt<=lnb; lnt++) markpixel(wd,lnt);
      wd++;
      ln += m;
     }
   }
  else
   {                                /* Stepping along paper length        */
    if(dl<0.0)
     {
      wd=wd1; ln=ln1;
      wdend  =wd0; lnend  =ln0;
      m = (dw/dl);
     }
    else
      if(dl>0.0)
       {
        wd=wd0; ln=ln0;
        wdend  =wd1; lnend  =ln1;
        m =  (dw/dl);
       }
     else
      {
       wd=wd1; ln=ln1;
       wdend  =wd1; lnend  =ln1;
       m=0.0;
      }

    while(ln<=lnend)
     {
      double wda=wd-hwid,wdb=wd+hwid,wdt;
      for(wdt=wda; wdt<=wdb; wdt++) markpixel(wdt,ln);
      ln++;
      wd += m;
     }
   }
 }


main(argc,argv)
 int argc;
 char *argv[];
 {
  char *pt;
  static char strip=0;
  int  i,split;
  double paperwd, paperln, stripln;
  double wdpointsmm, lnpointsmm, dummy;
  long wdpoints;
  long stpoints;
  long nrows;

#ifdef VMS
  unsigned res;
  unsigned ff=0x10;
  $DESCRIPTOR(devname,VERSATECDEV);
#else
  int nout,fno;
  int newmode[3];
#endif


  wdpointsmm=DEFWDPOINTSMM;
  lnpointsmm=DEFLNPOINTSMM;

  infile = NULL;
  outfile = NULL;

  if(argc==1)
   {
    printhelp();
    exit(1);
   }

  for(i=1; i<argc; i++)
   {                                     /* argument selection loop          */
    pt=argv[i];
    if((*pt=='-')||(*pt=='/'))
     {
      pt++;
      switch(*(pt++))
       {
        case 'w': case 'W':
         sscanf(pt,"%lf",&wdfact);
         break;

        case 'l': case 'L':
         sscanf(pt,"%lf",&lnfact);
         break;

        case 'c': case 'C':
         clip=TRUE;
         break;

        case 's': case 'S':
         split=TRUE;
         break;

        default: 
         printhelp();
         exit(1);
       }
     }
    else
     {
      if(*argv[i]=='?')
       {
        printhelp();
        return;
       }
                                               /* This is input file name    */
      if(infile==NULL) 
       {
        infile=fopen(pt,"r");
        if(infile==NULL)
         {
          fprintf(stderr,"\nVERSATEC - Error opening file %s for input\n",pt);
          return;
         }
       }
     }
   }

  if(infile==NULL) infile = stdin;

#ifdef VMS
  if((res=SYS$ALLOC(&devname,0,0,0))!=SS$_NORMAL) /* allocate device  */
  {
    fprintf(stderr,"ERROR! Cannot allocate device %s",VERSATECDEV);
    exit(1);
  }

  if((res=SYS$ASSIGN(&devname,&channel,0,0))!=SS$_NORMAL) /* assign a channel */
  {
    fprintf(stderr,"ERROR! Cannot assign channel to device %s",VERSATECDEV);
    exit(1);
  }
#else
  if((channel=fopen(VERSATECDEV,"ab"))==NULL)
  {
    fprintf(stderr,"ERROR! Device %s not present",VERSATECDEV);
    exit(1);
  }
  setbuf(channel,myoutbuffer);
  fno=fileno(channel);
  newmode[0]=VPLOT;
  newmode[1]=0;
  newmode[2]=0;
  ioctl(fno,VSETSTATE,newmode);
#endif

  fscanf(infile, " %lf %lf %lf\n", &paperwd, &paperln, &stripln );

  paperwd *= wdfact;
  stripln *= lnfact;

  wdpoints = paperwd * wdpointsmm + 0.5;   /* Strip limits in pixels       */
  stpoints = stripln * lnpointsmm + 0.5;   /* coordinates                  */

  if(wdpoints>DEFWDTOTPOINTS)           /* Check if graph fits into paper  */
   {
    if(!split)
     {
      if(!clip)
       {
        double rescal = (double) DEFWDTOTPOINTS / wdpoints;
        wdfact *= rescal;
        lnfact *= rescal;
        stpoints *= rescal;
       }
      wdpoints = DEFWDTOTPOINTS;
     }
   }
  else
   wdoffset=(DEFWDTOTPOINTS-wdpoints)/2;

  wdscale = wdpointsmm * wdfact;
  lnscale = lnpointsmm * lnfact;

  nrows = stpoints;

  getspace(nrows);                               /* allocate the bitmap   */

  nlines=0;

  do
  {
   do
   {
    double wd0,ln0,wd1,ln1;
    int width;
    double hwid,vwid;
    int n;

    nlines++;
    n=fscanf(infile, "%c %lf %lf %lf %lf %d\n",
                      &strip, &wd0, &ln0, &wd1, &ln1, &width );
    if(n != 6)
     {
      if(!feof(infile)) 
        printf("\nFormat error in line %ld of input file\n\n",nlines);
      break;
     }

    vwid = width*lnfact ;
    hwid = vwid*wdfact;

    rasterize(strip,wd0,ln0,wd1,ln1,hwid,vwid);
   }
   while (1);                 /* Do loop terminates on input eof           */
   writeout();                /* Write remaining strips                    */
   if(wdpoints>DEFWDTOTPOINTS)
     writeout();              /* Introduce a blank space between stripes   */
   lnoffset=0;                /* Reset length parameters                   */ 
   stripguard=nrows;
   wdoffset-=DEFWDTOTPOINTS;  /* Set new width offset                      */
   wdpoints-=DEFWDTOTPOINTS;  /* Set remaining width to plot               */
   csave='!';                 /* Reset strip identifier                    */
   rewind(infile);            /* Rewind input file to plot new stripe      */
   fscanf(infile, " %lf %lf %lf\n", &dummy, &dummy, &dummy);
                              /* Skip header                               */
  }
  while(split && wdpoints>0);
                     /* Do loop terminates when all stripes are writed out */
#ifdef VMS
					/* send a form feed		     */
  if((res=SYS$QIOW(0,channel,(short)(IO$_WRITEVBLK|IO$M_REMOTE),0,0,0,0,0,ff,
	0,0,0))!=SS$_NORMAL) printf("ERROR! Cannot write data to printer");
#else
  if(fflush(channel)) printf("ERROR! Cannot write data to printer");
  newmode[0]=VPRINT;
  ioctl(fno,VSETSTATE,newmode);
  write(fno,"\04",1);
#endif

					/* shut all                          */
#ifdef VMS
  if((res=SYS$DASSGN(channel))!=SS$_NORMAL)
  {
    printf("ERROR! Cannot deassign channel");
    exit(1);
  }

  if((res=SYS$DALLOC(&devname,0))!=SS$_NORMAL)
    printf("ERROR! Cannot dealloc device %s",VERSATECDEV);

  fclose(infile);
#else
  fclose(infile);
  fclose(channel);
#endif
  exit(0);
 }
