/*
 *
 *                       arc.c
 *
 * procedures for implementing AA, AR  instruction 
 *
 * Marek Krawus,   March '89
 */

#include "defn.h"

#define  expl   "ERROR: bad number of parameters in AA or AR instruction" 
#define  CCW    0 
#define  CW     1

arc( typ )
int   typ;
{
  float     X_inc;
  float     Y_inc;
  float     arc_angle;
  float     chord_angle;
  float     without_chord = 0.0;

  end_draw();

  if (test_token())   X_inc = getval();     /* in current unit */
  else   { fprintf(stderr, "%s\n",  expl); return; }

  if (test_token())   Y_inc = getval();     /* in current unit */
  else   { fprintf(stderr, "%s\n",  expl); return; }

  if (test_token())  {
    arc_angle = getval();  
/*    if (arc_angle != (float)rintx(arc_angle))   {
        fprintf(stderr, "ERROR: arc angle parameter in AR/AA instruction is \
not in integer format\n");
        return;
    }
*/
  }
  else   { fprintf(stderr, "%s\n",  expl); return; }

  if (test_token())  {
    chord_angle = getval();
/*    if (chord_angle != (float)rintx(chord_angle))   {
        fprintf(stderr, "ERROR: chord_angle parameter in AR/AA instruction is \
not in integer format\n");
        return;
    }
*/
    if ((chord_angle < -32768.0)||(chord_angle > 32767.0))   {
       fprintf(stderr, "ERROR: chord angle parameter in AR/AA instruction \
	      is out of range\n");
       return;
    }
    calculate_arc( typ, X_inc, Y_inc, arc_angle, chord_angle );
  }
  else  calculate_arc( typ, X_inc, Y_inc, arc_angle, without_chord); 
}

calculate_arc( typ, X, Y, angle, chord )
int       typ;
float     X;
float     Y;
float     angle; 
float     chord;

{
  float   Rad;
  float   xRad;
  float   yRad;
  float   start_angle;
  float   end_angle;
  float   xcentre;
  float   ycentre;
  float   xstart;
  float   ystart;
  float   xfinish;
  float   yfinish;
  int     cwiartka;
  float   alfa;
  int     fl;
  int     psi;
  int     angle_abs;
  int     psi_up;
  int     psi_down;
  int     start = 0;
  int     i;
  float   betarad;
  float   chord_size;
  float   gamma;
  float   epsilon;
  float   checkp();

  /* current pen position in current unit */
  xstart = absX / XSCALE;
  ystart = absY / YSCALE;

  if (typ == ABSOLUTE)  {
     xcentre = X;
     ycentre = Y;
  }
  else   {
     xcentre = xstart + X;
     ycentre = ystart + Y;
  } 

  if ((xcentre == xstart) && (ycentre == ystart))  {
    fprintf(stderr,"It is imposible to draw arc with zero-length radius\n");
    return;
  }

  /* now calculate radius   */

  Rad = pow((xstart - xcentre),2.0) + pow((ystart - ycentre),2.0);  
  Rad = pow(Rad, 0.5);   /* in current unit on plotter   */
  xRad = Rad * XSCALE;   /* in mm on PS output    */
  yRad = Rad * YSCALE;

  /* now: current pen position  relative to arc centre;
     it means  arc centre is in "temporary" coordinate system origin,
     start_angle ---> angle between centre__Xaxis and centre__current pen
		      position.
  */
  if ((xstart > xcentre)&&(ystart >= ycentre)) {
     cwiartka = 1;
     alfa = atan2( (ystart - ycentre), (xstart - xcentre) ); 
     start_angle = rad_deg * alfa;  
     goto mam;
  }
  if ((xstart <= xcentre)&&(ystart > ycentre)) {
     cwiartka = 2; 
     if (xstart == xcentre) start_angle = 90.0;
     else  {
	alfa = atan2( (ystart - ycentre), (xcentre - xstart) );
	start_angle = rad_deg * alfa;
	start_angle = 180.0 - start_angle;
     }
     goto mam;
  }
  if ((xstart < xcentre)&&(ystart <= ycentre)) {
     cwiartka = 3;
     alfa = atan2( (ycentre - ystart), (xcentre - xstart) );
     start_angle = rad_deg * alfa;
     start_angle += 180.0;
     goto mam;
  }
  if ((xstart >= xcentre)&&(ystart < ycentre)) {
     cwiartka = 4;
     if (xstart == xcentre) start_angle = 270.0;
     else   {
        alfa = atan2( (ycentre - ystart), (xstart - xcentre) );
	start_angle = rad_deg * alfa;
	start_angle = 360.0 - start_angle;
     }
     goto mam;
  }
mam:
  start_angle = (float)rintx(start_angle);

/* calculate end_angle  */
  if (angle < 0.0)  {
      fl = CW; 
      for(; angle < -360.0;) { angle += 360.0; } 
      end_angle = start_angle + angle;
      if (end_angle < 0.0) end_angle = 360.0 + end_angle;
  }
  else  {
      fl = CCW;
      for(; angle > 360.0;) { angle -= 360.0; }
      end_angle = start_angle + angle;
      if (end_angle > 360.0) end_angle -= 360.0;
  }

  end_angle = (float)rintx(end_angle);

 /*    calculate xfinish & yfinish  - pen position after instruction    */
  if (end_angle == 360.0) end_angle = 0.0;

  if ((end_angle >= 0.0)&&(end_angle < 90.0))  {
      xfinish = cos(deg_rad * end_angle) * Rad + xcentre;
      yfinish = sin(deg_rad * end_angle) * Rad + ycentre;
      goto koniec;
  }
  if ((end_angle >= 90.0)&&(end_angle < 180.0))  {
      xfinish = xcentre - (cos(deg_rad * (180.0 - end_angle)) * Rad);
      yfinish = sin(deg_rad * (180.0 - end_angle)) * Rad + ycentre;
      goto koniec;
  }
  if ((end_angle >= 180.0)&&(end_angle < 270.0))  {
      xfinish = xcentre - cos(deg_rad * (end_angle - 180.0)) * Rad;
      yfinish = ycentre - sin(deg_rad * (end_angle - 180.0)) * Rad;
      goto koniec;
  }
  if ((end_angle >= 270.0)&&(end_angle < 360.0))  {
      xfinish = cos(deg_rad * (360.0 - end_angle)) * Rad + xcentre;
      yfinish = ycentre - sin(deg_rad * (360.0 - end_angle)) * Rad;
      goto koniec;
  }

koniec:

 /* generally: it should be 'f' conversion character rather than 'g'
    for float values in 'printf' output function, in the whole program.
    The reason is: 'g' conversion character sometimes produces output
    in style 'e' (precision > 6 significant digits) and it will produce
    an error on the laser-writer.
    So, I must check xfinish & yfinish precision.
 */
  xfinish *= XSCALE;
  yfinish *= YSCALE;
  absX = checkp(xfinish);
  absY = checkp(yfinish);

 /* if angle parameter = 360 in AA/AR instructiom  */
      if (fabs(angle) == 360.0) end_angle = start_angle + 360.0;

  psi = rintx( chord );
  psi = abs(psi);
  if (psi > 360) psi = psi % 360;
  if (psi <= 5)  goto smooth;

  psi_up = psi_down = psi;
  angle_abs = abs((int)angle);
  if (angle_abs > psi)
                     while ((angle_abs % psi_up) != 0) psi_up++;
  while ((angle_abs % psi_down) != 0) psi_down--;
  if (angle_abs > psi)    
       psi = ((psi_up - psi) < (psi - psi_down))?(psi_up):(psi_down);
  else  psi = psi_down;
  if (psi <= 5) goto smooth;

  i = angle_abs / psi;
  betarad = deg_rad * (psi / 2.0);
  chord_size = 2 * xRad * sin(betarad);
  gamma = psi / 2.0;
  epsilon = 90.0 + gamma;

  
  if (PENDOWN == 1)
    fprintf(outfile, "%d %g %g %g %g %g %g %g %g %d %d Achord\n",
	   fl, xcentre * XSCALE, ycentre * YSCALE, xRad, yRad, start_angle,
	   end_angle,
	   chord_size, epsilon, psi, i);
    return;

smooth:
  if (PENDOWN == 1)
   fprintf(outfile, "%d %g %g %g %g %g %g Ellipse\n", fl, xcentre * XSCALE,
		     ycentre * YSCALE,
		     xRad, yRad, start_angle, end_angle);

}

float checkp( wart )
  float wart;
{
   int   i;
   float iwart;
   char   str[10];

   if ((wart < 0.1) && (wart > - 0.1)) return(0);

   for(i = 0; i < 10; str[i++] = '\0');

   sprintf(str,"%8f",wart);
   sscanf(str,"%f",&iwart); 
   return(iwart);
}

