/* @(#)bldgra.c	19.2 (ESO-DMD) 03/18/03 15:44:03 */
/*===========================================================================
  Copyright (C) 1995 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
===========================================================================*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.IDENTIFICATION
  function buildgra		version 2.50      860314
  K. Banse                  	ESO - Garching

.KEYWORDS
  vector, graphics

.PURPOSE
  compute (x,y) coordinates for given graph (shape)

.ALGORITHM
  depending on the shape, move along its contours + record "extreme" points

.VERSION

 030318		last modif

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

#include <math.h>
#include <midas_def.h>

#define MIN(a,b)      ((a)<(b))?(a):(b)
#define MAX(a,b)      ((a)>(b))?(a):(b)


/*

*/

void buildgra(shape,coords,arcs,xfig,yfig,figmax,nop)

char *shape;		/* IN: shape of graph,
			       [0,1] pure shape
					= RE, for rectangle
					= CI, for circle
					= EL, for ellipse
					= SL, for slit
					= AR, for arrow
					= LI, for line
					= CR, for cross
			       [2] shape_option
					= F, fill graph
					else not, for RE, CI,EL, SL
			       [2] = '1','2','3','4' for arrow direction */

int *coords;		/* IN: holds necessary input params for graph
			       dimension + meaning depends upon SHAPE
                               for REC: the two opposite coordinate pairs of
			                desired rectangle
				   CIR: center coords + radius
				   ELL: center coords + major, minor semiaxis
				   LIN: start + end coordinates
				   CRO: center coords + length */

float *arcs;		/* IN: only for CIRCLE, ELLIPS 
			       start + end angle of arc */
int *xfig;		/* OUT: array to hold x coords of created graph */
int *yfig;		/* OUT: array to hold y coords of created graph */
int figmax;		/* IN: max. size of `xfig' + `yfig' */
int *nop;		/* OUT: no. of points used in `xfig', `yfig' */

{

int  beginx, endx, beginy, endy;
int  ix, iy, k, n, n1, n2, noc, sw;
int  distx, center[2];

register int nr;

float radius, rconst, angle, angla, anglb, a, b, aa;

double twopi = 6.28318530710000012;	/*  2 * Pi */
double facto = 0.0174532925;		/*  Pi / 180. */


/*  branch according to shape */

if ((shape[0] == 'R') && (shape[1] == 'E'))
   {				/* construct coordinates for a rectangle */
   if (shape[2] != 'F')     
      {
      xfig[0] = coords[0];			/* start point */
      yfig[0] = coords[1];
      xfig[1] = coords[0];			/* move up... */
      yfig[1] = coords[3];
      xfig[2] = coords[2];			/* move right... */
      yfig[2] = coords[3];
      xfig[3] = coords[2];			/* move down... */
      yfig[3] = coords[1];
      xfig[4] = coords[0];		/* move left to start again... */
      yfig[4] = coords[1];
      *nop = 5;				/* going ri, up, le, do gave */
      }					/* problems some X11 servers ... */
   else
      {
      if (coords[1] < coords[3])
         {
         n1 = coords[1];
         n2 = coords[3];
         }
      else
         {
         n1 = coords[3];
         n2 = coords[1];
         }
      k = 0;
      sw = 0;
      for (nr=n1; nr<(n2+1); nr++)
         {
         xfig[k] = coords[sw];
         yfig[k] = nr;
         xfig[k+1] = coords[2-sw];
         yfig[k+1] = nr;
         k += 2;			/* increment counter */
         sw = 2 - sw;			/* and switch */
         }
      *nop = k;
      }
   }

else if ((shape[0] == 'C') && (shape[1] == 'I'))
   {                            /* construct coordinates for a circle */
   center[0] = coords[0];
   center[1] = coords[1];
   radius = coords[2];
   n = CGN_NINT(radius);
   if (n < 1)     
      n1 = 5 ;
   else if (n < 6)     
      n1 = 5 * n;
   else
      n1 = 8 * n;
   noc = MIN(figmax-1,n1);                   /* get no. of points to draw */
   rconst = twopi/noc ;
   angla = arcs[0]*facto; 
   anglb = arcs[1]*facto; 

   /*  loop through points on circle  */

   if (shape[2] != 'F')     
      {
      if (angla < 0.0)			/* direct call to buildgra... */
         {
         angle = 0.0;
         for (nr=0; nr<noc; nr++)
            {
            xfig[nr] = center[0] + CGN_NINT(radius*cos(angle));
            yfig[nr] = center[1] + CGN_NINT(radius*sin(angle));
            angle += rconst;
            }
         xfig[noc] = xfig[0];                   /* endpoint = startpoint */
         yfig[noc] = yfig[0];
         *nop = noc + 1;
         }
      else				/* draw arc (piece of circle) only */
         {
         noc ++;			/* we can take full count */
         angle = angla;
         for (nr=0; nr<noc; nr++)
            {
            xfig[nr] = center[0] + CGN_NINT(radius*cos(angle));
            yfig[nr] = center[1] + CGN_NINT(radius*sin(angle));
            angle += rconst;
            if (angle > anglb) break;
            }
         *nop = nr + 1;
         }
      }
   else
      {
      beginy = center[1] - radius;
      endy = center[1] + radius;
      xfig[0] = center[0];
      yfig[0] = beginy;
      n = 1;
      sw = -900;			/* start at -90. degrees */
      aa = 0.1 * facto;

      for (nr=beginy+1; nr<=endy; nr++)
         {
sect_2300:
         sw ++;
         if (sw > 900) break;
         angle = (float)sw * aa;	/* move in steps of 0.1 degree */
         iy = CGN_NINT(radius*sin(angle));
         n1 = center[1] + iy;               /* test y-value of circle */
         if (n1 < nr)     goto sect_2300;
 
         ix = CGN_NINT(radius*cos(angle));
         xfig[n] = center[0] + ix;
         yfig[n++] = center[1] + iy;
         xfig[n] = center[0] - ix;
         yfig[n] = yfig[n-1];
         n ++;
         xfig[n] = center[0] + ix;
         yfig[n] = yfig[n-1];
         n ++;
         }

      xfig[n] = center[0];
      yfig[n] = endy;
      *nop = n + 1;
      }
   }

else if ((shape[0] == 'L') && (shape[1] == 'I'))
   {                            /* construct coordinates for straight line */
   if ((shape[2] == '2') || (shape[2] == '3'))
      {
      xfig[0] = coords[0];
      yfig[0] = coords[3];
      xfig[1] = coords[2];
      yfig[1] = coords[1];
      }
   else
      {
      xfig[0] = coords[0];
      yfig[0] = coords[1];
      xfig[1] = coords[2];
      yfig[1] = coords[3];
      }
   *nop = 2;
   }

else if ((shape[0] == 'E') && (shape[1] == 'L'))
   {                            /* construct coordinates for an ellips */
   center[0] = (coords[0]+coords[2])/2;
   center[1] = (coords[1]+coords[3])/2;
   a = (coords[2]-coords[0]) * 0.5;		/* get major + minor axis */
   b = (coords[3]-coords[1]) * 0.5;
   aa = (a+b)/2;
   n2 = 5*CGN_NINT(aa);
   noc = MIN(figmax-1,n2);		/* get no. of points to draw */
   rconst = twopi/noc ;
   angla = arcs[0]*facto;
   anglb = arcs[1]*facto;


   /*  loop through points on ellipse */

   if (shape[2] != 'F')     
      {
      noc ++;
      if (angla < 0.0)			/* direct call to buildgra... */
         {
         angle = 0.0;
         for (nr=0; nr<noc; nr++)
            {
            xfig[nr] = center[0] + CGN_NINT(a*cos(angle));
            yfig[nr] = center[1] + CGN_NINT(b*sin(angle));
            angle += rconst;
            }
         *nop = noc;
         }
      else
         {
         angle = angla;
         for (nr=0; nr<noc; nr++)
            {
            xfig[nr] = center[0] + CGN_NINT(a*cos(angle));
            yfig[nr] = center[1] + CGN_NINT(b*sin(angle));
            angle += rconst;
            if (angle > anglb) break;
            }
         *nop = nr + 1;
         }
      }
   else
      {
      beginy = center[1] - CGN_NINT(b);
      endy = center[1] + CGN_NINT(b);
      xfig[0] = center[0];
      yfig[0] = beginy;
      n = 1;
      sw = -900;			/* start at -90. degrees */
      aa = 0.1 * facto; 

      for (nr=beginy+1; nr<=endy; nr++)
         {
sect_4300:
         sw ++;
         if (sw > 900) break;
         angle = (float)sw * aa;	/* move in steps of 0.1 degree */
         iy = CGN_NINT(b*sin(angle));
         n1 = center[1] + iy;               /* test y-value of circle */
         if (n1 < nr) goto sect_4300;

         ix = CGN_NINT(a*cos(angle));
         xfig[n] = center[0] + ix;
         yfig[n++] = center[1] + iy;
         xfig[n] = center[0] - ix;
         yfig[n] = yfig[n-1];
         n ++;
         xfig[n] = center[0] + ix;
         yfig[n] = yfig[n-1];
         n ++;
         }

      xfig[n] = center[0];
      yfig[n] = endy;
      *nop = n + 1;
      }
   }

else if ((shape[0] == 'C') && (shape[1] == 'R'))
   {                      /* construct coordinates of a cross (as closed fig */
   xfig[0] = coords[0];				/* start at bottom */
   yfig[0] = coords[1] - coords[2];
   xfig[1] = coords[0];				/* move to top... */
   yfig[1] = coords[1] + coords[2];
   xfig[2] = coords[0];				/* move down to center... */
   yfig[2] = coords[1];
   xfig[3] = coords[0] + coords[2];		/* move to right end... */
   yfig[3] = coords[1];
   xfig[4] = coords[0] - coords[2];		/* move to left end... */
   yfig[4] = coords[1];
   *nop = 5;
   }

else if ((shape[0] == 'A') && (shape[1] == 'R'))
   {                      /* construct coordinates of an arrow */
   if (shape[2] == '1')     
      {
      beginx = coords[0];
      beginy = coords[1];
      endx = coords[2];
      endy = coords[3];
      }
   else if (shape[2] == '2')
      {
      beginx = coords[0];
      beginy = coords[3];
      endx = coords[2];
      endy = coords[1];
      }
   else if (shape[2] == '3')
      {
      beginx = coords[2];
      beginy = coords[1];
      endx = coords[0];
      endy = coords[3];
      }
   else
      {
      beginx = coords[2];
      beginy = coords[3];
      endx = coords[0];
      endy = coords[1];
      }

   xfig[0] = beginx;
   yfig[0] = beginy;
   xfig[1] = endx;
   yfig[1] = endy;
   ix = endx - beginx;
   iy = endy - beginy;
   a = sqrt((float)(ix*ix) + (float)(iy*iy));	/* get length of arrow */
   b = a / 8.0;
   if (b < 2.0) b = 2.0;
   angle = atan2((float)iy,(float)ix);
   angle += (135. * facto);
   xfig[2] = endx + CGN_NINT(b*cos(angle));     /* move to left of top */
   yfig[2] = endy + CGN_NINT(b*sin(angle));
   xfig[3] = endx;				/* move back to top of arrow */
   yfig[3] = endy;
   angle += (90. * facto);
   xfig[4] = endx + CGN_NINT(b*cos(angle));     /* move to right of top */
   yfig[4] = endy + CGN_NINT(b*sin(angle));
   *nop = 5;
   }   

else if ((shape[0] == 'S') && (shape[1] == 'L'))
   {                     /* construct coordinates of a slit (as used in IUE) */
   xfig[0] = coords[0];			/* start at lower left corner */
   yfig[0] = coords[1];
   xfig[1] = coords[2];			/* move to right corner */
   yfig[1] = coords[1];

   center[0] = coords[2];
   center[1] = (coords[1]+coords[3])/2;
   radius = (coords[3]-coords[1])/2;
   if (shape[2] == 'F') goto sect_7500;   /* handle fill option farther down */

   noc = figmax-5;
   n1 = 10*CGN_NINT(radius);
   if (noc > n1) noc = n1;		/* take min */
   rconst = twopi/noc ;


  /*  loop through points on circle (but draw only outer half) */

   n = 2;
   aa = 90. * facto;
   for (nr=0; nr<(noc/2)+1; nr++)
      {
      angle = (nr * rconst) - aa;
      xfig[n] = center[0] + CGN_NINT(radius*cos(angle));
      yfig[n++] = center[1] + CGN_NINT(radius*sin(angle));
      }

   xfig[n] = coords[2];           /* make sure, we hit upper right corner */
   yfig[n++] = coords[3];
   xfig[n] = coords[0];           /* move to upper left corner */
   yfig[n++] = coords[3];
   center[0] = coords[0];


   /*  loop through points on circle (but draw only outer half)  */

   for (nr=(noc/2); nr<(noc+1); nr++)
      {
      angle = (nr * rconst) - aa;
      xfig[n] = center[0] + CGN_NINT(radius*cos(angle));
      yfig[n++] = center[1] + CGN_NINT(radius*sin(angle));
      }

   xfig[n] = coords[0];         /* make sure, we finish at lower left corner */
   yfig[n] = coords[1];
   *nop = n + 1;
   return;


   /*  here for filled slit */

sect_7500:
   beginy = coords[1];
   endy = coords[3];
   n = 2;
   sw = -900;			/* start at -90. degrees */
   aa = 0.1 * facto; 
   distx = coords[2] - coords[0];           /* size in x */

   for (nr=beginy+1; nr<=endy; nr++)
      {
sect_7800:
      sw ++;
      if (sw > 900) break;
      angle = (float)sw * aa;		/* move in steps of 0.1 degree */
      iy = CGN_NINT(radius*sin(angle));
      n1 = center[1] + iy;               /* test y-value of circle */
      if (n1 < nr) goto sect_7800;

      ix = CGN_NINT(radius*cos(angle));
      xfig[n] = center[0] + ix;
      yfig[n++] = center[1] + iy;
      xfig[n] = center[0] - ix -distx;		/* circle on other side... */
      yfig[n] = yfig[n-1];
      n ++;
      xfig[n] = center[0] + ix;
      yfig[n] = yfig[n-1];
      n ++;
      }

   xfig[n] = coords[0];
   yfig[n++] = endy;
   xfig[n] = coords[2];
   yfig[n] = endy;
   *nop = n + 1;
   }

else if ((shape[0] == 'T') && (shape[1] == 'R'))
   {                     /* construct coordinates of a triangle */
   xfig[0] = coords[0] ;
   yfig[0] = coords[1];
   xfig[1] = coords[2] ;
   yfig[1] = coords[3] ;
   xfig[2] = coords[4] ;
   yfig[2] = coords[5];
   xfig[3] = coords[0] ;
   yfig[3] = coords[1] ;
   *nop = 4;
   }
return;
}

